diff --git a/.project b/.project
new file mode 100644
index 0000000000..871dee54b0
--- /dev/null
+++ b/.project
@@ -0,0 +1,11 @@
+
+
+ RetroArch_
+
+
+
+
+
+
+
+
diff --git a/Makefile b/Makefile
index acf4054dbf..f7eb516e70 100644
--- a/Makefile
+++ b/Makefile
@@ -337,6 +337,11 @@ ifeq ($(DEBUG), 1)
OPTIMIZE_FLAG = -O0
endif
+ifeq ($(GL_DEBUG), 1)
+ CFLAGS += -DGL_DEBUG
+ CXXFLAGS += -DGL_DEBUG
+endif
+
CFLAGS += -Wall $(OPTIMIZE_FLAG) $(INCLUDE_DIRS) -g -I.
ifeq ($(CXX_BUILD), 1)
LD = $(CXX)
diff --git a/Makefile.emscripten b/Makefile.emscripten
new file mode 100644
index 0000000000..c1e913419c
--- /dev/null
+++ b/Makefile.emscripten
@@ -0,0 +1,159 @@
+TARGET = retroarch.js
+
+OBJ = frontend/frontend_emscripten.o \
+ retroarch.o \
+ file.o \
+ file_path.o \
+ driver.o \
+ conf/config_file.o \
+ settings.o \
+ hash.o \
+ dynamic.o \
+ dynamic_dummy.o \
+ message.o \
+ rewind.o \
+ movie.o \
+ gfx/gfx_common.o \
+ input/input_common.o \
+ input/rwebinput_input.o \
+ core_options.o \
+ patch.o \
+ compat/compat.o \
+ compat/rxml/rxml.o \
+ screenshot.o \
+ cheats.o \
+ audio/utils.o \
+ audio/rwebaudio.o \
+ input/overlay.o \
+ fifo_buffer.o \
+ gfx/scaler/scaler.o \
+ gfx/scaler/pixconv.o \
+ gfx/scaler/scaler_int.o \
+ gfx/scaler/filter.o \
+ gfx/state_tracker.o \
+ gfx/shader_parse.o \
+ gfx/fonts/fonts.o \
+ gfx/fonts/bitmapfont.o \
+ gfx/image.o \
+ audio/resampler.o \
+ audio/sinc.o \
+ audio/null.o \
+ performance.o
+
+HAVE_OPENGL = 1
+HAVE_RGUI = 1
+HAVE_SDL = 0
+HAVE_ZLIB = 1
+HAVE_FBO = 1
+WANT_MINIZ = 1
+MEMORY = 67108864
+LTO = 0
+FAST_DOUBLES = 1
+
+ifneq ($(NATIVE_ZLIB),)
+ WANT_MINIZ = 0
+endif
+
+libretro = libretro_emscripten.bc
+
+LIBS = -lm
+DEFINES = -DHAVE_SCREENSHOTS -DHAVE_NULLAUDIO -DHAVE_BSV_MOVIE -DPACKAGE_VERSION=\"0.9.9.3\"
+LDFLAGS = -L. -s TOTAL_MEMORY=$(MEMORY) --js-library emscripten/library_rwebaudio.js --js-library emscripten/library_rwebinput.js
+
+ifeq ($(PERF_TEST), 1)
+ DEFINES += -DPERF_TEST
+endif
+
+ifeq ($(HAVE_RGUI), 1)
+ DEFINES += -DHAVE_RGUI
+ OBJ += frontend/menu/menu_common.o frontend/menu/rgui.o frontend/menu/history.o
+endif
+
+ifeq ($(HAVE_SDL), 1)
+ OBJ += input/sdl_input.o
+ LIBS += -lSDL
+ DEFINES += -ISDL -DHAVE_SDL
+endif
+
+ifeq ($(HAVE_OPENGL), 1)
+ OBJ += gfx/gl.o gfx/math/matrix.o gfx/fonts/gl_font.o gfx/fonts/gl_raster_font.o gfx/gfx_context.o gfx/context/emscriptenegl_ctx.o gfx/shader_glsl.o gfx/glsym/rglgen.o gfx/glsym/glsym_es2.o
+ DEFINES += -DHAVE_OPENGL -DHAVE_OPENGLES -DHAVE_OPENGLES2 -DHAVE_EGL -DHAVE_OVERLAY -DHAVE_GLSL
+endif
+
+ifeq ($(HAVE_ZLIB), 1)
+ OBJ += gfx/rpng/rpng.o file_extract.o
+ DEFINES += -DHAVE_ZLIB
+ ifeq ($(WANT_MINIZ), 1)
+ OBJ += deps/miniz/miniz.o
+ DEFINES += -DWANT_MINIZ
+ else
+ LIBS += -lz
+ DEFINES += -DHAVE_ZLIB_DEFLATE
+ endif
+endif
+
+ifeq ($(HAVE_FBO), 1)
+ DEFINES += -DHAVE_FBO
+endif
+
+ifneq ($(V), 1)
+ Q := @
+endif
+
+ifeq ($(DEBUG), 1)
+ LDFLAGS += -O0 -g
+ CFLAGS += -O0 -g
+else
+ LDFLAGS += -O2
+ # WARNING: some optimizations can break some cores (ex: LTO breaks tyrquake)
+ ifeq ($(FAST_DOUBLES), 1)
+ LDFLAGS += -s DOUBLE_MODE=0
+ endif
+ ifeq ($(LTO), 1)
+ LDFLAGS += --llvm-lto 3
+ endif
+ CFLAGS += -O2
+endif
+
+CFLAGS += -Wall -Wno-unused-result -Wno-unused-variable -I. -std=gnu99
+
+all: $(TARGET)
+
+$(TARGET): $(OBJ)
+ @$(if $(Q), $(shell echo echo LD $@),)
+ $(Q)$(LD) -o $@ $(OBJ) $(libretro) $(LIBS) $(LDFLAGS)
+
+%.o: %.c
+ @$(if $(Q), $(shell echo echo CC $<),)
+ $(Q)$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
+
+%.o: %.cpp
+ @$(if $(Q), $(shell echo echo CXX $<),)
+ $(Q)$(CXX) $(CXXFLAGS) $(DEFINES) -c -o $@ $<
+
+clean:
+ rm -f *.o
+ rm -f deps/miniz/*.o
+ rm -f frontend/*.o
+ rm -f frontend/menu/*.o
+ rm -f audio/*.o
+ rm -f audio/xaudio-c/*.o
+ rm -f compat/*.o
+ rm -f compat/rxml/*.o
+ rm -f conf/*.o
+ rm -f gfx/scaler/*.o
+ rm -f gfx/*.o
+ rm -f gfx/d3d9/*.o
+ rm -f gfx/context/*.o
+ rm -f gfx/math/*.o
+ rm -f gfx/fonts/*.o
+ rm -f gfx/py_state/*.o
+ rm -f gfx/rpng/*.o
+ rm -f gfx/glsym/*.o
+ rm -f record/*.o
+ rm -f input/*.o
+ rm -f tools/*.o
+ rm -f $(TARGET)
+
+.PHONY: all clean
+
diff --git a/Makefile.win b/Makefile.win
index 3003c672b1..c05e716ab4 100644
--- a/Makefile.win
+++ b/Makefile.win
@@ -17,6 +17,7 @@ OBJ = frontend/frontend.o \
movie.o \
gfx/gfx_common.o \
input/input_common.o \
+ input/autoconf/builtin_win.o \
core_options.o \
patch.o \
compat/compat.o \
@@ -44,7 +45,8 @@ JOBJ := conf/config_file.o \
compat/compat.o \
file_path.o \
tools/input_common_joyconfig.o \
- input/dinput.o
+ input/dinput.o \
+ input/winxinput_joypad.o
CC = gcc
CXX = g++
@@ -62,6 +64,9 @@ HAVE_STDIN_CMD = 1
HAVE_THREADS = 1
HAVE_RGUI = 1
DYNAMIC = 1
+HAVE_WIN32GUI = 1
+
+HAVE_WINXINPUT = 1
ifeq ($(SLIM),)
HAVE_SDL = 1
@@ -78,7 +83,7 @@ endif
libretro ?= -lretro
LIBS = -lm
-DEFINES = -I. -DHAVE_SCREENSHOTS -DHAVE_BSV_MOVIE
+DEFINES = -I. -DHAVE_SCREENSHOTS -DHAVE_BSV_MOVIE -DHAVE_BUILTIN_AUTOCONFIG
LDFLAGS = -L. -static-libgcc
ifeq ($(TDM_GCC),)
@@ -100,6 +105,10 @@ ifeq ($(HAVE_RGUI), 1)
OBJ += frontend/menu/menu_common.o frontend/menu/rgui.o frontend/menu/history.o
endif
+ifeq ($(HAVE_WIN32GUI), 1)
+ DEFINES += -DHAVE_WIN32GUI
+endif
+
ifeq ($(HAVE_SDL), 1)
OBJ += gfx/sdl_gfx.o input/sdl_input.o input/sdl_joypad.o audio/sdl_audio.o
JOBJ += input/sdl_joypad.o
@@ -212,6 +221,11 @@ ifeq ($(HAVE_PYTHON), 1)
OBJ += gfx/py_state/py_state.o
endif
+ifeq ($(HAVE_WINXINPUT), 1)
+ DEFINES += -DHAVE_WINXINPUT
+ OBJ += input/winxinput_joypad.o
+endif
+
ifeq ($(HAVE_DINPUT), 1)
LIBS += -ldinput8 -ldxguid -lole32
DEFINES += -DHAVE_DINPUT
@@ -237,6 +251,11 @@ else
LDCXXFLAGS += -s
endif
+ifeq ($(GL_DEBUG), 1)
+ CFLAGS += -DGL_DEBUG
+ CXXFLAGS += -DGL_DEBUG
+endif
+
CFLAGS += -Wall -Wno-unused-result -Wno-unused-variable -I.
CXXFLAGS += -Wall -Wno-unused-result -Wno-unused-variable -I. -std=c++0x -D__STDC_CONSTANT_MACROS
ifeq ($(CXX_BUILD), 1)
@@ -301,10 +320,10 @@ clean:
rm -f tools/*.o
dist_x86: all
- zip -r retroarch-win32-0.9.9.4.zip $(TARGET) $(JTARGET) retroarch.cfg
+ zip -r retroarch-win32-0.9.9.6.zip $(TARGET) $(JTARGET) retroarch.cfg
dist_x86_64: all
- zip -r retroarch-win64-0.9.9.4.zip $(TARGET) $(JTARGET) retroarch.cfg
+ zip -r retroarch-win64-0.9.9.6.zip $(TARGET) $(JTARGET) retroarch.cfg
libs_x86:
wget http://themaister.net/retroarch-dl/RetroArch-win32-libs.zip
diff --git a/android/native/jni/Android.mk b/android/native/jni/Android.mk
index 7a2e6b963c..063c0aeb2e 100644
--- a/android/native/jni/Android.mk
+++ b/android/native/jni/Android.mk
@@ -48,7 +48,7 @@ ifeq ($(PERF_TEST), 1)
LOCAL_CFLAGS += -DPERF_TEST
endif
-LOCAL_CFLAGS += -Wall -pthread -Wno-unused-function -O3 -fno-stack-protector -funroll-loops -DNDEBUG -DRARCH_MOBILE -DHAVE_GRIFFIN -DANDROID -DHAVE_DYNAMIC -DHAVE_OPENGL -DHAVE_FBO -DHAVE_OVERLAY -DHAVE_OPENGLES -DHAVE_VID_CONTEXT -DHAVE_OPENGLES2 -DGLSL_DEBUG -DHAVE_GLSL -DHAVE_RGUI -DHAVE_SCREENSHOTS -DWANT_MINIZ -DHAVE_ZLIB -DINLINE=inline -DLSB_FIRST -DHAVE_THREADS -D__LIBRETRO__ -DRARCH_PERFORMANCE_MODE -std=gnu99 -I../../../deps/miniz
+LOCAL_CFLAGS += -Wall -pthread -Wno-unused-function -O3 -fno-stack-protector -funroll-loops -DNDEBUG -DRARCH_MOBILE -DHAVE_GRIFFIN -DANDROID -DHAVE_DYNAMIC -DHAVE_OPENGL -DHAVE_FBO -DHAVE_OVERLAY -DHAVE_OPENGLES -DHAVE_VID_CONTEXT -DHAVE_OPENGLES2 -DGLSL_DEBUG -DHAVE_GLSL -DHAVE_RGUI -DHAVE_SCREENSHOTS -DWANT_MINIZ -DHAVE_ZLIB -DINLINE=inline -DLSB_FIRST -DHAVE_THREADS -D__LIBRETRO__ -std=gnu99 -I../../../deps/miniz
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -landroid -lEGL -lGLESv2 $(LOGGER_LDLIBS) -ldl
diff --git a/android/native/jni/input_android.c b/android/native/jni/input_android.c
index f34b69c8ff..65c13625f2 100644
--- a/android/native/jni/input_android.c
+++ b/android/native/jni/input_android.c
@@ -423,7 +423,7 @@ static void android_input_set_keybinds(void *data, unsigned device,
break;
case DEVICE_GAMEMID:
g_settings.input.device[port] = device;
- g_settings.input.dpad_emulation[port] = ANALOG_DPAD_NONE;
+ g_settings.input.dpad_emulation[port] = ANALOG_DPAD_DUALANALOG;
strlcpy(g_settings.input.device_names[port], "GameMID",
sizeof(g_settings.input.device_names[port]));
@@ -1190,6 +1190,7 @@ static void android_input_set_keybinds(void *data, unsigned device,
strlcpy(g_settings.input.device_names[port], "OUYA",
sizeof(g_settings.input.device_names[port]));
+ g_settings.input.dpad_emulation[port] = ANALOG_DPAD_DUALANALOG;
keycode_lut[AKEYCODE_DPAD_UP] |= ((RETRO_DEVICE_ID_JOYPAD_UP+1) << shift);
keycode_lut[AKEYCODE_DPAD_DOWN] |= ((RETRO_DEVICE_ID_JOYPAD_DOWN+1) << shift);
keycode_lut[AKEYCODE_DPAD_LEFT] |= ((RETRO_DEVICE_ID_JOYPAD_LEFT+1) << shift);
@@ -1228,6 +1229,7 @@ static void android_input_set_keybinds(void *data, unsigned device,
g_settings.input.device[port] = device;
strlcpy(g_settings.input.device_names[port], "Xperia Play",
sizeof(g_settings.input.device_names[port]));
+ g_settings.input.dpad_emulation[port] = ANALOG_DPAD_NONE;
if ((zeus_second_id != -1 && (zeus_second_id == id)))
{
@@ -1592,8 +1594,9 @@ static void android_input_set_keybinds(void *data, unsigned device,
static void android_input_poll(void *data)
{
int ident;
+ uint64_t lifecycle_mask = (1ULL << RARCH_RESET) | (1ULL << RARCH_REWIND) | (1ULL << RARCH_FAST_FORWARD_KEY) | (1ULL << RARCH_FAST_FORWARD_HOLD_KEY) | (1ULL << RARCH_MUTE) | (1ULL << RARCH_SAVE_STATE_KEY) | (1ULL << RARCH_LOAD_STATE_KEY) | (1ULL << RARCH_STATE_SLOT_PLUS) | (1ULL << RARCH_STATE_SLOT_MINUS) | (1ULL << RARCH_QUIT_KEY) | (1ULL << RARCH_MENU_TOGGLE);
uint64_t *lifecycle_state = &g_extern.lifecycle_state;
- *lifecycle_state &= ~((1ULL << RARCH_RESET) | (1ULL << RARCH_REWIND) | (1ULL << RARCH_FAST_FORWARD_KEY) | (1ULL << RARCH_FAST_FORWARD_HOLD_KEY) | (1ULL << RARCH_MUTE) | (1ULL << RARCH_SAVE_STATE_KEY) | (1ULL << RARCH_LOAD_STATE_KEY) | (1ULL << RARCH_STATE_SLOT_PLUS) | (1ULL << RARCH_STATE_SLOT_MINUS) | (1ULL << RARCH_QUIT_KEY));
+ *lifecycle_state &= ~lifecycle_mask;
while ((ident = ALooper_pollAll((input_key_pressed_func(RARCH_PAUSE_TOGGLE)) ? -1 : 0,
NULL, NULL, NULL)) >= 0)
@@ -1752,9 +1755,6 @@ static void android_input_poll(void *data)
}
else if (type_event == AINPUT_EVENT_TYPE_KEY)
{
- if (debug_enable)
- snprintf(msg, sizeof(msg), "Pad %d : %d, ac = %d, src = %d.\n", state_id, keycode, action, source);
-
/* Hack - we have to decrease the unpacked value by 1
* because we 'added' 1 to each entry in the LUT -
* RETRO_DEVICE_ID_JOYPAD_B is 0
@@ -1764,20 +1764,25 @@ static void android_input_poll(void *data)
int action = AKeyEvent_getAction(event);
uint64_t *key = NULL;
- if(input_state < (1ULL << RARCH_FIRST_META_KEY))
+ if (debug_enable)
+ snprintf(msg, sizeof(msg), "Pad %d : %d, ac = %d, src = %d.\n", state_id, keycode, action, source);
+
+ if (input_state < (1ULL << RARCH_FIRST_META_KEY))
key = &state[state_id];
- else if(input_state)
+ else if (input_state/* && action == AKEY_EVENT_ACTION_DOWN*/)
key = &g_extern.lifecycle_state;
- if(key != NULL)
+ if (key != NULL)
{
- if (action == AKEY_EVENT_ACTION_UP)
+ // some controllers send both the up and down events at once when the button is released for "special" buttons, like menu buttons
+ // work around that by only using down events for meta keys (which get cleared every poll anyway)
+ if (action == AKEY_EVENT_ACTION_UP && !(input_state & lifecycle_mask))
*key &= ~(input_state);
else if (action == AKEY_EVENT_ACTION_DOWN)
*key |= input_state;
}
- if((keycode == AKEYCODE_VOLUME_UP || keycode == AKEYCODE_VOLUME_DOWN) && keycode_lut[keycode] == 0)
+ if ((keycode == AKEYCODE_VOLUME_UP || keycode == AKEYCODE_VOLUME_DOWN) && keycode_lut[keycode] == 0)
handled = 0;
}
@@ -1851,7 +1856,7 @@ static int16_t android_input_state(void *data, const struct retro_keybind **bind
static bool android_input_key_pressed(void *data, int key)
{
- return ((g_extern.lifecycle_state | driver.overlay_state) & (1ULL << key));
+ return ((g_extern.lifecycle_state | driver.overlay_state.buttons) & (1ULL << key));
}
static void android_input_free_input(void *data)
diff --git a/android/phoenix/.classpath b/android/phoenix/.classpath
index c06dfcb8e5..51769745b2 100644
--- a/android/phoenix/.classpath
+++ b/android/phoenix/.classpath
@@ -1,7 +1,7 @@
-
+
diff --git a/android/phoenix/AndroidManifest.xml b/android/phoenix/AndroidManifest.xml
index d0dc0587b0..051ccabc81 100644
--- a/android/phoenix/AndroidManifest.xml
+++ b/android/phoenix/AndroidManifest.xml
@@ -1,7 +1,7 @@
+ android:versionCode="24"
+ android:versionName="0.9.9.6" >
+
-
+
@@ -28,10 +29,12 @@
+
+
diff --git a/android/phoenix/assets/libretro_cores.cfg b/android/phoenix/assets/libretro_cores.cfg
index 468fbf0ae3..9255e899f4 100644
--- a/android/phoenix/assets/libretro_cores.cfg
+++ b/android/phoenix/assets/libretro_cores.cfg
@@ -1,26 +1,81 @@
-libretro_mednafen_pce_fast = "Mednafen PCE-fast (PC Engine/PC Engine CD)"
-libretro_mednafen_wswan = "Mednafen WSwan (Wonderswan)"
-libretro_fceumm = "FCEUmm (Nintendo NES)"
-libretro_mednafen_vb = "Mednafen VB (Virtual Boy)"
-libretro_fba = "Final Burn Alpha (Arcade)"
-libretro_mednafen_ngp = "Mednafen NGP (Neo-Geo Pocket)"
-libretro_mednafen_psx = "Mednafen PSX (PlayStation1)"
-libretro_gambatte = "Gambatte (GameBoy/GameBoy Color)"
-libretro_genesis_plus_gx = "Genesis Plus GX (Sega Genesis/Sega CD/Master System)"
-libretro_picodrive = "Picodrive (Sega Genesis/Sega CD/Master System/32X)"
-libretro_vba_next = "VBA Next (GameBoy Advance)"
-libretro_prboom = "PrBoom (DOOM)"
-libretro_snes9x = "SNES9x (Nintendo SNES)"
-libretro_snes9x_next = "SNES9x Next (Nintendo SNES)"
-libretro_nestopia = "Nestopia (Nintendo NES)"
-libretro_pcsx_rearmed-neon = "PCSX-reARMed (PlayStation1) [NEON]"
-libretro_pcsx_rearmed = "PCSX-reARMed (PlayStation1)"
-libretro_nxengine = "NXEngine (Cave Story/Doukutsu Monogatari)"
-libretro_quicknes = "QuickNES (Nintendo NES)"
-libretro_tyrquake = "TyrQuake (Quake 1)"
-libretro_instancingviewer = "InstancingViewer (Images)"
-libretro_desmume = "Desmume (Nintendo DS)"
-libretro_stella = "Stella (Atari 2600)"
-libretro_scenewalker = "SceneWalker (Objects)"
-libretro_modelviewer = "ModelViewer (Objects)"
-libretro_mame078 = "MAME 2003 [0.78] (Arcade)"
+libretro_mednafen_pce_fast = "Mednafen PCE-fast"
+libretro_mednafen_pce_fast_system = "PC Engine/PC Engine CD"
+
+libretro_mednafen_wswan = "Mednafen WSwan"
+libretro_mednafen_wswan_system = "Wonderswan"
+
+libretro_fceumm = "FCEUmm"
+libretro_fceumm_system = "Nintendo NES"
+
+libretro_mednafen_vb = "Mednafen VB"
+libretro_mednafen_vb_system = "Virtual Boy"
+
+libretro_fba = "Final Burn Alpha"
+libretro_fba_system = "Arcade"
+
+libretro_mednafen_ngp = "Mednafen NGP"
+libretro_mednafen_ngp_system = "Neo-Geo Pocket"
+
+libretro_mednafen_psx = "Mednafen PSX"
+libretro_mednafen_psx_system = "PlayStation1"
+
+libretro_gambatte = "Gambatte"
+libretro_gambatte_system = "GameBoy/GameBoy Color"
+
+libretro_genesis_plus_gx = "Genesis Plus GX"
+libretro_genesis_plus_gx_system = "Sega Genesis/Sega CD/Master System"
+
+libretro_picodrive = "Picodrive"
+libretro_picodrive_system = "Sega Genesis/Sega CD/Master System/32X"
+
+libretro_vba_next = "VBA Next"
+libretro_vba_next_system = "GameBoy Advance"
+
+libretro_prboom = "PrBoom"
+libretro_prboom_system = "DOOM"
+
+libretro_snes9x = "SNES9x"
+libretro_snes9x_system = "Nintendo SNES"
+
+libretro_snes9x_next = "SNES9x Next"
+libretro_snes9x_next_system = "Nintendo SNES"
+
+libretro_nestopia = "Nestopia"
+libretro_nestopia_system = "Nintendo NES"
+
+libretro_pcsx_rearmed-neon = "PCSX-reARMed [NEON]"
+libretro_pcsx_rearmed-neon_system = "PlayStation1"
+
+libretro_pcsx_rearmed = "PCSX-reARMed"
+libretro_pcsx_rearmed_system = "PlayStation1"
+
+libretro_nxengine = "NXEngine"
+libretro_nxengine_system = "Cave Story/Doukutsu Monogatari"
+
+libretro_quicknes = "QuickNES"
+libretro_quicknes_system = "Nintendo NES"
+
+libretro_tyrquake = "TyrQuake"
+libretro_tyrquake_system = "Quake 1"
+
+libretro_instancingviewer = "InstancingViewer"
+libretro_instancingviewer_system = "Images"
+
+libretro_desmume = "Desmume"
+libretro_desmume_system = "Nintendo DS"
+
+libretro_stella = "Stella"
+libretro_stella_system = "Atari 2600"
+
+libretro_scenewalker = "SceneWalker"
+libretro_scenewalker_system = "Objects"
+
+libretro_modelviewer = "ModelViewer"
+libretro_modelviewer_system = "Objects"
+
+libretro_mame078 = "MAME 2003 [0.78]"
+libretro_mame078_system = "Arcade"
+
+libretro_bsnes_performance = "bsnes/higan Performance"
+libretro_bsnes_performance_system = "Nintendo SNES"
+
diff --git a/android/phoenix/res/layout/assets.xml b/android/phoenix/res/layout/assets.xml
new file mode 100644
index 0000000000..afb702997c
--- /dev/null
+++ b/android/phoenix/res/layout/assets.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
diff --git a/android/phoenix/res/layout/faq_whats_new.xml b/android/phoenix/res/layout/faq_whats_new.xml
index 6465cc312d..7d7df4c389 100644
--- a/android/phoenix/res/layout/faq_whats_new.xml
+++ b/android/phoenix/res/layout/faq_whats_new.xml
@@ -10,6 +10,49 @@
android:layout_height="wrap_content"
android:layout_margin="40px"
android:text="
+ r21 (August 16, 2013)\n\n
+ * [VBA Next] Fixes serious regressions - most evident in Golden Sun games -\n
+ battle screens etc.\n
+ * [VBA Next] Add a core option to change the control button layout from (left\n
+ to right) B to A to (left to right) A to B.\n
+ r19 (August 15, 2013)\n\n
+ * [Android] Input autodetection fixes -\n
+ - DualShock3 pad controls fixed\n
+ * [Android] It should now be possible to map D-pad to analog on several gamepads, such as:\n
+ - Xbox 360\n
+ - PlayStation3\n
+ - Shield\n
+ * [Android] Threaded video is now the default due to positive user feedback. Purists and accuracy\n
+ people can still go for static syncing for best results - although for PCSX ReARMed threaded\n
+ video is essential. With the combination of threaded video and dynamic audio rate control,\n
+ most of the audio pops and sync issues should be a thing of the past now. Yay.\n
+ * [Android] UI has been reorganized and made less shitty (yes, we know). Still a long way to go.\n
+ The entire menu should be gamepad-controllable now at least - handy for Shield/Ouya.\n
+ * [Android] Shaders that were broken on Nexus 7/4/10 etc. should now work.\n
+ * [Android] Added some additional autodetection rules:\n
+ - Ouya: Input overlays are disabled by default\n
+ * [Android] Added high-latency audio option for crappy/old Android devices that can't handle\n
+ the lower-latency audio that is the default since 0.9.9.4. This should give you the same\n
+ performance as 0.9.9.3 (r17). Turn this on if you get bad sound/performance (and it's not your\n
+ device simply being slow). This might also apply for some of the newer devices - perhaps \n
+ OpenSL driver has not been updated/optimized there.\n
+* [Android] Added a TV mode. This will launch you straight into RGUI mode. This mode
+is identical to what you get from the Wii and PC ports of RetroArch at startup. First
+you select a core, then you select a game to go with it.
+* [SNES9x] Fixes by Alcaro to libretro port
+* [SNES9x Next] Fixes savestates from not being able to be loaded.
+ * (LIBRETRO) Added bsnes/higan performance core [v0.92] (Android).\n
+ - bsnes/higan performance core will run all non-coprocessor games at fullspeed on an\n
+ nVidia Shield.\n
+ - Co-processor games (SuperFX/SA-1/DSP/Cx4/SA1) will run between ~40fps and 55-57fps\n
+ on an nVidia Shield - depending on the specific co-processor. Note - you will need\n
+ BIOS files for these games - see byuu boards for information on them.\n
+ * [Mednafen NGP] Fixes input issues in a number of games, such as:\n
+ - Card Fighters games\n
+ - Etc.\n
+ * [Picodrive] Updates/32X compatibility/accuracy improvements\n
+ * [NEStopia] Updated to 1.46 WIP - added ability to load NstDatabase.xml, fixes Vs. System games\n
+ and Startropics 1/2\n
r18 (August 7, 2013)\n\n
* [Android] ANR issues fixed - Google bug (as ever).\n
* [Android] Input autodetection expanded -\n
diff --git a/android/phoenix/res/layout/line_list_item.xml b/android/phoenix/res/layout/line_list_item.xml
index 46ebf2dec1..6c9d14e3d3 100644
--- a/android/phoenix/res/layout/line_list_item.xml
+++ b/android/phoenix/res/layout/line_list_item.xml
@@ -3,7 +3,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
- android:layout_height="48dp">
+ android:layout_height="wrap_content">
-
-
+ android:layout_gravity="center_vertical"
+ android:orientation="vertical" >
+
+
+
+
+
diff --git a/android/phoenix/res/values/array.xml b/android/phoenix/res/values/array.xml
index 823710ca5f..d25dc54553 100644
--- a/android/phoenix/res/values/array.xml
+++ b/android/phoenix/res/values/array.xml
@@ -10,6 +10,20 @@
- 1
+
+ - 64ms (Low)
+ - 96ms (Medium)
+ - 128ms (Medium)
+ - 160ms (High)
+
+
+
+ - 64
+ - 96
+ - 128
+ - 160
+
+
- Full screen
- Auto
diff --git a/android/phoenix/res/values/strings.xml b/android/phoenix/res/values/strings.xml
index e37ebf04c3..530ed1c704 100644
--- a/android/phoenix/res/values/strings.xml
+++ b/android/phoenix/res/values/strings.xml
@@ -9,5 +9,6 @@
Report Refresh Rate
Detect
Optimal device settings
+ Extracting assets, please wait ...
diff --git a/android/phoenix/res/xml/prefs.xml b/android/phoenix/res/xml/prefs.xml
index 0b3142b73c..91a0b3c118 100644
--- a/android/phoenix/res/xml/prefs.xml
+++ b/android/phoenix/res/xml/prefs.xml
@@ -1,12 +1,27 @@
+ android:title="RetroArch - Main Menu" >
-
+
+
+
+
+
+
+
+
+
+
@@ -98,11 +114,19 @@
android:summary="Enable dynamic rate control (recommended)."
android:title="Dynamic Rate Control"
android:dependency="audio_enable" />
+
@@ -111,10 +135,22 @@
+
+
+
+
+
+
+
+
+
+
+
adapter;
- static private final int ACTIVITY_LOAD_ROM = 0;
- static private String libretro_path;
static private final String TAG = "CoreSelection";
- private ConfigFile config;
- private ConfigFile core_config;
-
- private final double getDisplayRefreshRate() {
- // Android is *very* likely to screw this up.
- // It is rarely a good value to use, so make sure it's not
- // completely wrong. Some phones return refresh rates that are completely bogus
- // (like 0.3 Hz, etc), so try to be very conservative here.
- final WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
- final Display display = wm.getDefaultDisplay();
- double rate = display.getRefreshRate();
- if (rate > 61.0 || rate < 58.0)
- rate = 59.95;
- return rate;
- }
-
- private final double getRefreshRate() {
- double rate = 0;
- SharedPreferences prefs = PreferenceManager
- .getDefaultSharedPreferences(getBaseContext());
- String refresh_rate = prefs.getString("video_refresh_rate", "");
- if (!refresh_rate.isEmpty()) {
- try {
- rate = Double.parseDouble(refresh_rate);
- } catch (NumberFormatException e) {
- Log.e(TAG, "Cannot parse: " + refresh_rate + " as a double!");
- rate = getDisplayRefreshRate();
- }
- } else {
- rate = getDisplayRefreshRate();
- }
-
- Log.i(TAG, "Using refresh rate: " + rate + " Hz.");
- return rate;
- }
-
- private String readCPUInfo() {
- String result = "";
-
- try {
- BufferedReader br = new BufferedReader(new InputStreamReader(
- new FileInputStream("/proc/cpuinfo")));
-
- String line;
- while ((line = br.readLine()) != null)
- result += line + "\n";
- br.close();
- } catch (IOException ex) {
- ex.printStackTrace();
- }
- return result;
- }
-
- private boolean cpuInfoIsNeon(String info) {
- return info.contains("neon");
- }
-
-
@Override
public void onCreate(Bundle savedInstanceState) {
+ ConfigFile core_config;
super.onCreate(savedInstanceState);
-
- try {
- config = new ConfigFile(new File(getDefaultConfigPath()));
- } catch (IOException e) {
- config = new ConfigFile();
- }
-
+
core_config = new ConfigFile();
try {
core_config.append(getAssets().open("libretro_cores.cfg"));
} catch (IOException e) {
Log.e(TAG, "Failed to load libretro_cores.cfg from assets.");
}
-
- String cpuInfo = readCPUInfo();
- boolean cpuIsNeon = cpuInfoIsNeon(cpuInfo);
-
+
+ String cpuInfo = MainMenuActivity.readCPUInfo();
+ boolean cpuIsNeon = cpuInfo.contains("neon");
+
setContentView(R.layout.line_list);
// Setup the list
@@ -116,15 +44,16 @@ public class CoreSelection extends Activity implements
setTitle("Select Libretro core");
// Populate the list
- final String modulePath = getApplicationInfo().nativeLibraryDir;
+ final String modulePath = MainMenuActivity.getInstance()
+ .getApplicationInfo().nativeLibraryDir;
final File[] libs = new File(modulePath).listFiles();
for (final File lib : libs) {
String libName = lib.getName();
-
+
// Never append a NEON lib if we don't have NEON.
if (libName.contains("neon") && !cpuIsNeon)
continue;
-
+
// If we have a NEON version with NEON capable CPU,
// never append a non-NEON version.
if (cpuIsNeon && !libName.contains("neon")) {
@@ -132,18 +61,20 @@ public class CoreSelection extends Activity implements
for (final File lib_ : libs) {
String otherName = lib_.getName();
String baseName = libName.replace(".so", "");
- if (otherName.contains("neon") && otherName.startsWith(baseName)) {
+ if (otherName.contains("neon")
+ && otherName.startsWith(baseName)) {
hasNeonVersion = true;
break;
}
}
-
+
if (hasNeonVersion)
continue;
}
-
+
// Allow both libretro-core.so and libretro_core.so.
- if (libName.startsWith("libretro") && !libName.startsWith("libretroarch")) {
+ if (libName.startsWith("libretro")
+ && !libName.startsWith("libretroarch")) {
try {
adapter.add(new ModuleWrapper(this, lib, core_config));
} catch (IOException e) {
@@ -151,235 +82,16 @@ public class CoreSelection extends Activity implements
}
}
}
-
+
this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
-
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
- this.registerForContextMenu(findViewById(android.R.id.content));
- }
}
@Override
public void onItemClick(AdapterView> aListView, View aView,
int aPosition, long aID) {
final ModuleWrapper item = adapter.getItem(aPosition);
- libretro_path = item.file.getAbsolutePath();
-
- Intent myIntent;
- myIntent = new Intent(this, ROMActivity.class);
- startActivityForResult(myIntent, ACTIVITY_LOAD_ROM);
- }
-
- private String getDefaultConfigPath() {
- String internal = System.getenv("INTERNAL_STORAGE");
- String external = System.getenv("EXTERNAL_STORAGE");
-
- if (external != null) {
- String confPath = external + File.separator + "retroarch.cfg";
- if (new File(confPath).exists())
- return confPath;
- } else if (internal != null) {
- String confPath = internal + File.separator + "retroarch.cfg";
- if (new File(confPath).exists())
- return confPath;
- } else {
- String confPath = "/mnt/extsd/retroarch.cfg";
- if (new File(confPath).exists())
- return confPath;
- }
-
- if (internal != null && new File(internal + File.separator + "retroarch.cfg").canWrite())
- return internal + File.separator + "retroarch.cfg";
- else if (external != null && new File(internal + File.separator + "retroarch.cfg").canWrite())
- return external + File.separator + "retroarch.cfg";
- else if ((getApplicationInfo().dataDir) != null)
- return (getApplicationInfo().dataDir) + File.separator + "retroarch.cfg";
- else // emergency fallback, all else failed
- return "/mnt/sd/retroarch.cfg";
- }
-
- @TargetApi(17)
- private int getLowLatencyOptimalSamplingRate() {
- AudioManager manager = (AudioManager)getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
- return Integer.parseInt(manager.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE));
- }
-
- private int getOptimalSamplingRate() {
- int ret;
- if (android.os.Build.VERSION.SDK_INT >= 17)
- ret = getLowLatencyOptimalSamplingRate();
- else
- ret = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);
-
- Log.i(TAG, "Using sampling rate: " + ret + " Hz");
- return ret;
- }
-
- private void updateConfigFile() {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
- config.setBoolean("audio_rate_control", prefs.getBoolean("audio_rate_control", true));
- config.setInt("audio_out_rate", getOptimalSamplingRate());
- config.setInt("audio_latency", prefs.getBoolean("audio_high_latency", false) ? 160 : 64);
- config.setBoolean("audio_enable", prefs.getBoolean("audio_enable", true));
- config.setBoolean("video_smooth", prefs.getBoolean("video_smooth", true));
- config.setBoolean("video_allow_rotate", prefs.getBoolean("video_allow_rotate", true));
- config.setBoolean("savestate_auto_load", prefs.getBoolean("savestate_auto_load", true));
- config.setBoolean("savestate_auto_save", prefs.getBoolean("savestate_auto_save", false));
- config.setBoolean("rewind_enable", prefs.getBoolean("rewind_enable", false));
- config.setBoolean("video_vsync", prefs.getBoolean("video_vsync", true));
- config.setBoolean("input_autodetect_enable", prefs.getBoolean("input_autodetect_enable", true));
- config.setBoolean("input_debug_enable", prefs.getBoolean("input_debug_enable", false));
- config.setInt("input_back_behavior", Integer.valueOf(prefs.getString("input_back_behavior", "0")));
- config.setInt("input_autodetect_icade_profile_pad1", Integer.valueOf(prefs.getString("input_autodetect_icade_profile_pad1", "0")));
- config.setInt("input_autodetect_icade_profile_pad2", Integer.valueOf(prefs.getString("input_autodetect_icade_profile_pad2", "0")));
- config.setInt("input_autodetect_icade_profile_pad3", Integer.valueOf(prefs.getString("input_autodetect_icade_profile_pad3", "0")));
- config.setInt("input_autodetect_icade_profile_pad4", Integer.valueOf(prefs.getString("input_autodetect_icade_profile_pad4", "0")));
-
- config.setDouble("video_refresh_rate", getRefreshRate());
- config.setBoolean("video_threaded", prefs.getBoolean("video_threaded", true));
-
- String aspect = prefs.getString("video_aspect_ratio", "auto");
- if (aspect.equals("full")) {
- config.setBoolean("video_force_aspect", false);
- } else if (aspect.equals("auto")) {
- config.setBoolean("video_force_aspect", true);
- config.setBoolean("video_force_aspect_auto", true);
- config.setDouble("video_aspect_ratio", -1.0);
- } else if (aspect.equals("square")) {
- config.setBoolean("video_force_aspect", true);
- config.setBoolean("video_force_aspect_auto", false);
- config.setDouble("video_aspect_ratio", -1.0);
- } else {
- double aspect_ratio = Double.parseDouble(aspect);
- config.setBoolean("video_force_aspect", true);
- config.setDouble("video_aspect_ratio", aspect_ratio);
- }
-
- config.setBoolean("video_scale_integer", prefs.getBoolean("video_scale_integer", false));
-
- String shaderPath = prefs.getString("video_shader", "");
- config.setString("video_shader", shaderPath);
- config.setBoolean("video_shader_enable",
- prefs.getBoolean("video_shader_enable", false)
- && new File(shaderPath).exists());
-
- boolean useOverlay = prefs.getBoolean("input_overlay_enable", true);
- if (useOverlay) {
- String overlayPath = prefs.getString("input_overlay", (getApplicationInfo().dataDir) + "/overlays/snes-landscape.cfg");
- config.setString("input_overlay", overlayPath);
- config.setDouble("input_overlay_opacity", prefs.getFloat("input_overlay_opacity", 1.0f));
- } else {
- config.setString("input_overlay", "");
- }
-
- config.setString("savefile_directory", prefs.getBoolean("savefile_directory_enable", false) ?
- prefs.getString("savefile_directory", "") : "");
- config.setString("savestate_directory", prefs.getBoolean("savestate_directory_enable", false) ?
- prefs.getString("savestate_directory", "") : "");
- config.setString("system_directory", prefs.getBoolean("system_directory_enable", false) ?
- prefs.getString("system_directory", "") : "");
-
- config.setBoolean("video_font_enable", prefs.getBoolean("video_font_enable", true));
-
- for (int i = 1; i <= 4; i++)
- {
- final String btns[] = {"up", "down", "left", "right", "a", "b", "x", "y", "start", "select", "l", "r", "l2", "r2", "l3", "r3" };
- for (String b : btns)
- {
- String p = "input_player" + String.valueOf(i) + "_" + b + "_btn";
- config.setInt(p, prefs.getInt(p, 0));
- }
- }
-
- String confPath = getDefaultConfigPath();
- try {
- config.write(new File(confPath));
- } catch (IOException e) {
- Log.e(TAG, "Failed to save config file to: " + confPath);
- }
- }
-
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- Intent myIntent;
- String current_ime = Settings.Secure.getString(getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
-
- updateConfigFile();
-
- switch (requestCode) {
- case ACTIVITY_LOAD_ROM:
- if (data.getStringExtra("PATH") != null) {
- Toast.makeText(this,
- "Loading: [" + data.getStringExtra("PATH") + "]...",
- Toast.LENGTH_SHORT).show();
- myIntent = new Intent(this, RetroActivity.class);
- myIntent.putExtra("ROM", data.getStringExtra("PATH"));
- myIntent.putExtra("LIBRETRO", libretro_path);
- myIntent.putExtra("CONFIGFILE", getDefaultConfigPath());
- myIntent.putExtra("IME", current_ime);
- startActivity(myIntent);
- }
- break;
- }
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu aMenu) {
- super.onCreateOptionsMenu(aMenu);
- getMenuInflater().inflate(R.menu.directory_list, aMenu);
- return true;
- }
-
- public void showPopup(View v) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
- {
- PopupMenuAbstract menu = new PopupMenuAbstract(this, v);
- MenuInflater inflater = menu.getMenuInflater();
- inflater.inflate(R.menu.context_menu, menu.getMenu());
- menu.setOnMenuItemClickListener(new PopupMenuAbstract.OnMenuItemClickListener()
- {
- @Override
- public boolean onMenuItemClick(MenuItem item) {
- return onContextItemSelected(item);
- }
-
- });
- menu.show();
- }
- else
- {
- this.openContextMenu(findViewById(android.R.id.content));
- }
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View v,
- ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, v, menuInfo);
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.context_menu, menu);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem aItem) {
- switch (aItem.getItemId()) {
- case R.id.settings:
- showPopup(findViewById(R.id.settings));
- return true;
-
- default:
- return super.onOptionsItemSelected(aItem);
- }
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.input_method_select:
- InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
- imm.showInputMethodPicker();
- return true;
- default:
- return false;
- }
+ MainMenuActivity.getInstance().setModule(item.file.getAbsolutePath(), item.getText());
+ MainMenuActivity.getInstance().updateConfigFile();
+ finish();
}
}
diff --git a/android/phoenix/src/org/retroarch/browser/DirectoryActivity.java b/android/phoenix/src/org/retroarch/browser/DirectoryActivity.java
index 5199054ff1..4ba900fe0a 100644
--- a/android/phoenix/src/org/retroarch/browser/DirectoryActivity.java
+++ b/android/phoenix/src/org/retroarch/browser/DirectoryActivity.java
@@ -9,7 +9,6 @@ import android.content.*;
import android.app.*;
import android.media.AudioManager;
import android.os.*;
-import android.preference.PreferenceManager;
import android.widget.*;
import android.view.*;
@@ -107,7 +106,7 @@ public class DirectoryActivity extends Activity implements
private void finishWithPath(String path) {
if (pathSettingKey != null && !pathSettingKey.isEmpty()) {
- SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
+ SharedPreferences settings = MainMenuActivity.getPreferences();
SharedPreferences.Editor editor = settings.edit();
editor.putString(pathSettingKey, path);
editor.commit();
diff --git a/android/phoenix/src/org/retroarch/browser/DisplayRefreshRateTest.java b/android/phoenix/src/org/retroarch/browser/DisplayRefreshRateTest.java
index 7b25728792..22df6cedbd 100644
--- a/android/phoenix/src/org/retroarch/browser/DisplayRefreshRateTest.java
+++ b/android/phoenix/src/org/retroarch/browser/DisplayRefreshRateTest.java
@@ -8,7 +8,6 @@ import android.content.SharedPreferences;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
-import android.preference.PreferenceManager;
import android.util.Log;
import android.view.WindowManager;
import android.widget.Toast;
@@ -36,7 +35,7 @@ public class DisplayRefreshRateTest extends Activity {
}
private void setFPSSetting(double fps) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
+ SharedPreferences prefs = MainMenuActivity.getPreferences();
SharedPreferences.Editor edit = prefs.edit();
edit.putString("video_refresh_rate", Double.valueOf(fps).toString());
edit.commit();
@@ -117,7 +116,7 @@ public class DisplayRefreshRateTest extends Activity {
@Override
protected void onDestroy() {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
+ SharedPreferences prefs = MainMenuActivity.getPreferences();
String fps = prefs.getString("video_refresh_rate", "ERROR");
Toast.makeText(this, "Refresh rate measured to: " + fps + " Hz.", Toast.LENGTH_LONG).show();
super.onDestroy();
diff --git a/android/phoenix/src/org/retroarch/browser/FileWrapper.java b/android/phoenix/src/org/retroarch/browser/FileWrapper.java
index 8af274db16..afbd0fbd54 100644
--- a/android/phoenix/src/org/retroarch/browser/FileWrapper.java
+++ b/android/phoenix/src/org/retroarch/browser/FileWrapper.java
@@ -43,6 +43,11 @@ class FileWrapper implements IconAdapterItem {
else
return file.getName();
}
+
+ @Override
+ public String getSubText() {
+ return null;
+ }
@Override
public int getIconResourceId() {
diff --git a/android/phoenix/src/org/retroarch/browser/HistorySelection.java b/android/phoenix/src/org/retroarch/browser/HistorySelection.java
new file mode 100644
index 0000000000..f35b32c26d
--- /dev/null
+++ b/android/phoenix/src/org/retroarch/browser/HistorySelection.java
@@ -0,0 +1,84 @@
+package org.retroarch.browser;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+import org.retroarch.R;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ListView;
+import android.widget.Toast;
+
+public class HistorySelection extends Activity implements
+ AdapterView.OnItemClickListener {
+
+ private IconAdapter adapter;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.line_list);
+
+ // Setup the list
+ adapter = new IconAdapter(this, R.layout.line_list_item);
+ ListView list = (ListView) findViewById(R.id.list);
+ list.setAdapter(adapter);
+ list.setOnItemClickListener(this);
+
+ setTitle("Recently played games");
+
+ File history = new File(getApplicationInfo().dataDir, "retroarch-history.txt");
+
+ try {
+ BufferedReader br = new BufferedReader(new InputStreamReader(
+ new FileInputStream(history)));
+
+ for (;;) {
+ String game = br.readLine();
+ String core = br.readLine();
+ String name = br.readLine();
+ if (game == null || core == null || name == null)
+ break;
+
+ adapter.add(new HistoryWrapper(game, core, name));
+ }
+ br.close();
+ } catch (IOException ex) {
+ }
+ }
+
+ @Override
+ public void onItemClick(AdapterView> aListView, View aView,
+ int aPosition, long aID) {
+ final HistoryWrapper item = adapter.getItem(aPosition);
+ final String gamePath = item.getGamePath();
+ final String corePath = item.getCorePath();
+
+ MainMenuActivity.getInstance().setModule(corePath, item.getCoreName());
+
+ Intent myIntent;
+ String current_ime = Settings.Secure.getString(getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD);
+
+ MainMenuActivity.getInstance().updateConfigFile();
+
+ Toast.makeText(this, "Loading: [" + gamePath + "] ...",
+ Toast.LENGTH_SHORT).show();
+ myIntent = new Intent(this, RetroActivity.class);
+ myIntent.putExtra("ROM", gamePath);
+ myIntent.putExtra("LIBRETRO", corePath);
+ myIntent.putExtra("CONFIGFILE", MainMenuActivity.getDefaultConfigPath());
+ myIntent.putExtra("IME", current_ime);
+ startActivity(myIntent);
+ finish();
+ }
+}
diff --git a/android/phoenix/src/org/retroarch/browser/HistoryWrapper.java b/android/phoenix/src/org/retroarch/browser/HistoryWrapper.java
new file mode 100644
index 0000000000..ae57f1c149
--- /dev/null
+++ b/android/phoenix/src/org/retroarch/browser/HistoryWrapper.java
@@ -0,0 +1,63 @@
+package org.retroarch.browser;
+
+import java.io.File;
+
+import android.graphics.drawable.Drawable;
+
+public class HistoryWrapper implements IconAdapterItem {
+
+ private String gamePath;
+ private String gamePathShort;
+ private String corePath;
+ private String coreName;
+
+ public HistoryWrapper(String gamePath, String corePath, String coreName) {
+ this.gamePath = gamePath;
+ this.corePath = corePath;
+ this.coreName = coreName;
+
+ File file = new File(gamePath);
+ gamePathShort = file.getName();
+ try {
+ gamePathShort = gamePathShort.substring(0, gamePathShort.lastIndexOf('.'));
+ } catch (Exception e) {
+ }
+ }
+
+ public String getGamePath() {
+ return gamePath;
+ }
+
+ public String getCorePath() {
+ return corePath;
+ }
+
+ public String getCoreName() {
+ return coreName;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return true;
+ }
+
+ @Override
+ public String getText() {
+ return gamePathShort;
+ }
+
+ @Override
+ public String getSubText() {
+ return coreName;
+ }
+
+ @Override
+ public int getIconResourceId() {
+ return 0;
+ }
+
+ @Override
+ public Drawable getIconDrawable() {
+ return null;
+ }
+}
diff --git a/android/phoenix/src/org/retroarch/browser/HoneycombPopupMenu.java b/android/phoenix/src/org/retroarch/browser/HoneycombPopupMenu.java
deleted file mode 100644
index ca4026a913..0000000000
--- a/android/phoenix/src/org/retroarch/browser/HoneycombPopupMenu.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package org.retroarch.browser;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.os.Build;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.PopupMenu;
-
-@TargetApi(Build.VERSION_CODES.HONEYCOMB)
-class HoneycombPopupMenu extends LazyPopupMenu {
- private PopupMenu instance;
- HoneycombPopupMenu.OnMenuItemClickListener listen;
-
- public HoneycombPopupMenu(Context context, View anchor)
- {
- instance = new PopupMenu(context, anchor);
- }
-
- @Override
- public void setOnMenuItemClickListener(HoneycombPopupMenu.OnMenuItemClickListener listener)
- {
- listen = listener;
- instance.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
- @Override
- public boolean onMenuItemClick(MenuItem item) {
- return listen.onMenuItemClick(item);
- }
-
- });
- }
-
- @Override
- public Menu getMenu() {
- return instance.getMenu();
- }
-
- @Override
- public MenuInflater getMenuInflater() {
- return instance.getMenuInflater();
- }
-
- @Override
- public void show() {
- instance.show();
- }
-}
diff --git a/android/phoenix/src/org/retroarch/browser/IMEActivity.java b/android/phoenix/src/org/retroarch/browser/IMEActivity.java
new file mode 100644
index 0000000000..cfe1f55cd4
--- /dev/null
+++ b/android/phoenix/src/org/retroarch/browser/IMEActivity.java
@@ -0,0 +1,16 @@
+package org.retroarch.browser;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.inputmethod.InputMethodManager;
+
+public class IMEActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.showInputMethodPicker();
+ finish();
+ }
+}
diff --git a/android/phoenix/src/org/retroarch/browser/IconAdapter.java b/android/phoenix/src/org/retroarch/browser/IconAdapter.java
index 72314daf0f..5d1a2c9f64 100644
--- a/android/phoenix/src/org/retroarch/browser/IconAdapter.java
+++ b/android/phoenix/src/org/retroarch/browser/IconAdapter.java
@@ -10,11 +10,9 @@ import android.widget.*;
interface IconAdapterItem {
public abstract boolean isEnabled();
-
public abstract String getText();
-
+ public abstract String getSubText();
public abstract int getIconResourceId();
-
public abstract Drawable getIconDrawable();
}
@@ -23,7 +21,6 @@ class IconAdapter extends ArrayAdapter {
public IconAdapter(Activity aContext, int aLayout) {
super(aContext, aLayout);
-
layout = aLayout;
}
@@ -45,6 +42,16 @@ class IconAdapter extends ArrayAdapter {
textView.setText(item.getText());
textView.setEnabled(enabled);
}
+
+ textView = (TextView) aConvertView.findViewById(R.id.sub_name);
+ if (null != textView) {
+ String subText = item.getSubText();
+ if (null != subText) {
+ textView.setVisibility(View.VISIBLE);
+ textView.setEnabled(item.isEnabled());
+ textView.setText(subText);
+ }
+ }
ImageView imageView = (ImageView) aConvertView.findViewById(R.id.icon);
if (null != imageView) {
diff --git a/android/phoenix/src/org/retroarch/browser/LazyPopupMenu.java b/android/phoenix/src/org/retroarch/browser/LazyPopupMenu.java
deleted file mode 100644
index 9e72cb5622..0000000000
--- a/android/phoenix/src/org/retroarch/browser/LazyPopupMenu.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.retroarch.browser;
-
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-
-abstract class LazyPopupMenu {
- public abstract Menu getMenu();
- public abstract MenuInflater getMenuInflater();
- public abstract void setOnMenuItemClickListener(LazyPopupMenu.OnMenuItemClickListener listener);
- public abstract void show();
- public interface OnMenuItemClickListener {
- public abstract boolean onMenuItemClick(MenuItem item);
- }
-}
\ No newline at end of file
diff --git a/android/phoenix/src/org/retroarch/browser/MainMenuActivity.java b/android/phoenix/src/org/retroarch/browser/MainMenuActivity.java
index 1e8f81284f..679fae917d 100644
--- a/android/phoenix/src/org/retroarch/browser/MainMenuActivity.java
+++ b/android/phoenix/src/org/retroarch/browser/MainMenuActivity.java
@@ -1,71 +1,497 @@
package org.retroarch.browser;
-import java.io.BufferedOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
+import java.io.*;
import org.retroarch.R;
+import android.annotation.TargetApi;
import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
import android.content.DialogInterface;
+import android.content.Intent;
import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetManager;
import android.media.AudioManager;
+import android.media.AudioTrack;
import android.os.Bundle;
+import android.os.Handler;
+import android.preference.CheckBoxPreference;
+import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceManager;
+import android.provider.Settings;
import android.util.Log;
+import android.view.Display;
+import android.view.WindowManager;
import android.widget.Toast;
public class MainMenuActivity extends PreferenceActivity {
+ private static MainMenuActivity instance = null;
+ static private final int ACTIVITY_LOAD_ROM = 0;
static private final String TAG = "MainMenu";
+ static private String libretro_path;
+ static private String libretro_name;
+
+ private boolean globalConfigEnable = true;
+
@SuppressWarnings("deprecation")
+ private void refreshPreferenceScreen() {
+ readbackConfigFile();
+
+ setPreferenceScreen(null);
+ addPreferencesFromResource(R.xml.prefs);
+
+ setCoreTitle(libretro_name);
+ PreferenceManager.setDefaultValues(this, R.xml.prefs, false);
+
+ final CheckBoxPreference param = (CheckBoxPreference) findPreference("global_config_enable");
+ globalConfigEnable = param.isChecked();
+ param.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ updateConfigFile();
+ globalConfigEnable = param.isChecked();
+ SharedPreferences prefs = MainMenuActivity.getPreferences();
+ SharedPreferences.Editor edit = prefs.edit();
+ edit.putBoolean("global_config_enable", param.isChecked());
+ edit.commit();
+
+ refreshPreferenceScreen();
+ return true;
+ }
+ });
+ }
+
+ private boolean usePerCoreConfig() {
+ boolean config_same_as_native_lib_dir = libretro_path
+ .equals(getApplicationInfo().nativeLibraryDir);
+
+ return !globalConfigEnable && !config_same_as_native_lib_dir;
+ }
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- addPreferencesFromResource(R.xml.prefs);
- PreferenceManager.setDefaultValues(this, R.xml.prefs, false);
+ instance = this;
+
+ SharedPreferences prefs = getPreferences();
+
+ libretro_path = prefs.getString("libretro_path", getApplicationInfo().nativeLibraryDir);
+ libretro_name = prefs.getString("libretro_name", "No core");
+
+ refreshPreferenceScreen();
+
this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
-
- // Extracting assets appears to take considerable amount of time, so
- // move extraction to a thread.
- Thread assetThread = new Thread(new Runnable() {
- public void run() {
- extractAssets();
- }
- });
- assetThread.start();
-
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
-
+
+ extractAssets();
+
if (!prefs.getBoolean("first_time_refreshrate_calculate", false)) {
- prefs.edit().putBoolean("first_time_refreshrate_calculate", true).commit();
-
- if (!detectDevice(false))
- {
- AlertDialog.Builder alert = new AlertDialog.Builder(this)
- .setTitle("Welcome to RetroArch")
- .setMessage("This is your first time starting up RetroArch. RetroArch will now be preconfigured for the best possible gameplay experience. Please be aware that it might take some time until all shader and overlay assets are extracted.\n\nNOTE: Advanced users who want to finetune for the best possible audio/video experience should use static synchronization and turn off threaded video. Be aware that this is hard to configure right and might result in unpleasant audio crackles when it has been configured wrong.\n\nThreaded video should work fine on most devices, but applies some adaptive video jittering to achieve this. ")
- .setPositiveButton("OK", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
- SharedPreferences.Editor edit = prefs.edit();
- edit.putBoolean("video_threaded", true);
- edit.commit();
- }
- });
- alert.show();
+ prefs.edit().putBoolean("first_time_refreshrate_calculate", true)
+ .commit();
+
+ if (!detectDevice(false)) {
+ AlertDialog.Builder alert = new AlertDialog.Builder(this)
+ .setTitle("Welcome to RetroArch")
+ .setMessage(
+ "This is your first time starting up RetroArch. RetroArch will now be preconfigured for the best possible gameplay experience.")
+ .setPositiveButton("OK", null);
+ alert.show();
}
}
+
+ Intent startedByIntent = getIntent();
+ if (null != startedByIntent.getStringExtra("ROM")
+ && null != startedByIntent.getStringExtra("LIBRETRO")) {
+ if (null == savedInstanceState
+ || !savedInstanceState.getBoolean("romexec"))
+ loadRomExternal(startedByIntent.getStringExtra("ROM"),
+ startedByIntent.getStringExtra("LIBRETRO"));
+ else
+ finish();
+ }
+ }
+
+ public static MainMenuActivity getInstance() {
+ return instance;
+ }
+
+ private final double getDisplayRefreshRate() {
+ // Android is *very* likely to screw this up.
+ // It is rarely a good value to use, so make sure it's not
+ // completely wrong. Some phones return refresh rates that are
+ // completely bogus
+ // (like 0.3 Hz, etc), so try to be very conservative here.
+ final WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
+ final Display display = wm.getDefaultDisplay();
+ double rate = display.getRefreshRate();
+ if (rate > 61.0 || rate < 58.0)
+ rate = 59.95;
+ return rate;
+ }
+
+ public static final double getRefreshRate() {
+ double rate = 0;
+ SharedPreferences prefs = getPreferences();
+ String refresh_rate = prefs.getString("video_refresh_rate", "");
+ if (!refresh_rate.isEmpty()) {
+ try {
+ rate = Double.parseDouble(refresh_rate);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "Cannot parse: " + refresh_rate + " as a double!");
+ rate = getInstance().getDisplayRefreshRate();
+ }
+ } else {
+ rate = getInstance().getDisplayRefreshRate();
+ }
+
+ Log.i(TAG, "Using refresh rate: " + rate + " Hz.");
+ return rate;
+ }
+
+ public static String readCPUInfo() {
+ String result = "";
+
+ try {
+ BufferedReader br = new BufferedReader(new InputStreamReader(
+ new FileInputStream("/proc/cpuinfo")));
+
+ String line;
+ while ((line = br.readLine()) != null)
+ result += line + "\n";
+ br.close();
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ return result;
+ }
+
+ @TargetApi(17)
+ public static int getLowLatencyOptimalSamplingRate() {
+ AudioManager manager = (AudioManager) getInstance()
+ .getApplicationContext()
+ .getSystemService(Context.AUDIO_SERVICE);
+ return Integer.parseInt(manager
+ .getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE));
}
+ @TargetApi(17)
+ public static int getLowLatencyBufferSize() {
+ AudioManager manager = (AudioManager) getInstance()
+ .getApplicationContext()
+ .getSystemService(Context.AUDIO_SERVICE);
+ int buffersize = Integer.parseInt(manager
+ .getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER));
+ Log.i(TAG, "Queried ideal buffer size (frames): " + buffersize);
+ return buffersize;
+ }
+
+ @TargetApi(17)
+ public static boolean hasLowLatencyAudio() {
+ PackageManager pm = getInstance().getPackageManager();
+ return pm.hasSystemFeature(PackageManager.FEATURE_AUDIO_LOW_LATENCY);
+ }
+
+ public static int getOptimalSamplingRate() {
+ int ret;
+ if (android.os.Build.VERSION.SDK_INT >= 17)
+ ret = getLowLatencyOptimalSamplingRate();
+ else
+ ret = AudioTrack
+ .getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);
+
+ Log.i(TAG, "Using sampling rate: " + ret + " Hz");
+ return ret;
+ }
+
+ private static String sanitizeLibretroPath(String path) {
+ String sanitized_name = path.substring(
+ path.lastIndexOf("/") + 1,
+ path.lastIndexOf("."));
+ sanitized_name = sanitized_name.replace("neon", "");
+ sanitized_name = sanitized_name.replace("libretro_", "");
+ return sanitized_name;
+ }
+
+ public static String getDefaultConfigPath() {
+ String internal = System.getenv("INTERNAL_STORAGE");
+ String external = System.getenv("EXTERNAL_STORAGE");
+
+ String append_path;
+ if (getInstance().usePerCoreConfig()) {
+ String sanitized_name = sanitizeLibretroPath(libretro_path);
+ append_path = File.separator + sanitized_name + ".cfg";
+ } else {
+ append_path = File.separator + "retroarch.cfg";
+ }
+
+ if (external != null) {
+ String confPath = external + append_path;
+ if (new File(confPath).exists())
+ return confPath;
+ } else if (internal != null) {
+ String confPath = internal + append_path;
+ if (new File(confPath).exists())
+ return confPath;
+ } else {
+ String confPath = "/mnt/extsd" + append_path;
+ if (new File(confPath).exists())
+ return confPath;
+ }
+
+ if (internal != null && new File(internal + append_path).canWrite())
+ return internal + append_path;
+ else if (external != null
+ && new File(internal + append_path).canWrite())
+ return external + append_path;
+ else if ((getInstance().getApplicationInfo().dataDir) != null)
+ return (getInstance().getApplicationInfo().dataDir)
+ + append_path;
+ else
+ // emergency fallback, all else failed
+ return "/mnt/sd" + append_path;
+ }
+
+ private void readbackString(ConfigFile cfg, SharedPreferences.Editor edit, String key) {
+ if (cfg.keyExists(key))
+ edit.putString(key, cfg.getString(key));
+ else
+ edit.remove(key);
+ }
+
+ private void readbackBool(ConfigFile cfg, SharedPreferences.Editor edit, String key) {
+ if (cfg.keyExists(key))
+ edit.putBoolean(key, cfg.getBoolean(key));
+ else
+ edit.remove(key);
+ }
+
+ private void readbackDouble(ConfigFile cfg, SharedPreferences.Editor edit, String key) {
+ if (cfg.keyExists(key))
+ edit.putFloat(key, (float)cfg.getDouble(key));
+ else
+ edit.remove(key);
+ }
+
+ private void readbackFloat(ConfigFile cfg, SharedPreferences.Editor edit, String key) {
+ if (cfg.keyExists(key))
+ edit.putFloat(key, cfg.getFloat(key));
+ else
+ edit.remove(key);
+ }
+
+ private void readbackInt(ConfigFile cfg, SharedPreferences.Editor edit, String key) {
+ if (cfg.keyExists(key))
+ edit.putInt(key, cfg.getInt(key));
+ else
+ edit.remove(key);
+ }
+
+ public void readbackConfigFile() {
+ String path = getDefaultConfigPath();
+ ConfigFile config;
+ try {
+ config = new ConfigFile(new File(path));
+ } catch (IOException e) {
+ return;
+ }
+
+ Log.i(TAG, "Config readback from: " + path);
+
+ SharedPreferences prefs = getPreferences();
+ SharedPreferences.Editor edit = prefs.edit();
+
+ readbackString(config, edit, "rgui_browser_directory");
+ readbackString(config, edit, "savefile_directory");
+ readbackString(config, edit, "savestate_directory");
+ readbackBool(config, edit, "savefile_directory_enable"); // Ignored by RetroArch
+ readbackBool(config, edit, "savestate_directory_enable"); // Ignored by RetroArch
+
+ readbackString(config, edit, "input_overlay");
+ readbackBool(config, edit, "input_overlay_enable");
+ readbackBool(config, edit, "video_scale_integer");
+ readbackBool(config, edit, "video_smooth");
+ readbackBool(config, edit, "video_threaded");
+ readbackBool(config, edit, "rewind_enable");
+ readbackBool(config, edit, "savestate_auto_load");
+ readbackBool(config, edit, "savestate_auto_save");
+ //readbackDouble(config, edit, "video_refresh_rate");
+
+ readbackBool(config, edit, "audio_rate_control");
+ readbackBool(config, edit, "audio_enable");
+ // TODO: other audio settings
+
+ readbackDouble(config, edit, "input_overlay_opacity");
+ readbackBool(config, edit, "input_autodetect_enable");
+ //readbackInt(config, edit, "input_back_behavior");
+
+ readbackBool(config, edit, "video_allow_rotate");
+ readbackBool(config, edit, "video_font_enable");
+
+ readbackBool(config, edit, "video_vsync");
+
+ edit.commit();
+ }
+
+ public void updateConfigFile() {
+ String path = getDefaultConfigPath();
+ ConfigFile config;
+ try {
+ config = new ConfigFile(new File(path));
+ } catch (IOException e) {
+ config = new ConfigFile();
+ }
+
+ Log.i(TAG, "Writing config to: " + path);
+
+ SharedPreferences prefs = getPreferences();
+
+ config.setString("libretro_path", libretro_path);
+
+ config.setString("rgui_browser_directory",
+ prefs.getString("rgui_browser_directory", ""));
+ config.setBoolean("audio_rate_control",
+ prefs.getBoolean("audio_rate_control", true));
+
+ int optimalRate = getOptimalSamplingRate();
+ config.setInt("audio_out_rate", optimalRate);
+
+ // Refactor this entire mess and make this usable for per-core config
+ if (android.os.Build.VERSION.SDK_INT >= 17 &&
+ prefs.getBoolean("audio_latency_auto", true) == true) {
+ int buffersize = getLowLatencyBufferSize();
+
+ boolean lowLatency = hasLowLatencyAudio();
+ Log.i(TAG, "Audio is low latency: " + (lowLatency ? "yes" : "no"));
+
+ config.setInt("audio_latency", 64);
+ if (lowLatency) {
+ config.setInt("audio_block_frames", buffersize);
+ } else {
+ config.setInt("audio_block_frames", 0);
+ }
+ } else {
+ String latency_audio = prefs.getString("audio_latency", "64");
+ config.setInt("audio_latency", Integer.parseInt(latency_audio));
+ }
+
+ config.setBoolean("audio_enable",
+ prefs.getBoolean("audio_enable", true));
+ config.setBoolean("video_smooth",
+ prefs.getBoolean("video_smooth", true));
+ config.setBoolean("video_allow_rotate",
+ prefs.getBoolean("video_allow_rotate", true));
+ config.setBoolean("savestate_auto_load",
+ prefs.getBoolean("savestate_auto_load", true));
+ config.setBoolean("savestate_auto_save",
+ prefs.getBoolean("savestate_auto_save", false));
+ config.setBoolean("rewind_enable",
+ prefs.getBoolean("rewind_enable", false));
+ config.setBoolean("video_vsync", prefs.getBoolean("video_vsync", true));
+ config.setBoolean("input_autodetect_enable",
+ prefs.getBoolean("input_autodetect_enable", true));
+ config.setBoolean("input_debug_enable",
+ prefs.getBoolean("input_debug_enable", false));
+ config.setInt("input_back_behavior",
+ Integer.valueOf(prefs.getString("input_back_behavior", "0")));
+ config.setInt("input_autodetect_icade_profile_pad1", Integer
+ .valueOf(prefs.getString("input_autodetect_icade_profile_pad1",
+ "0")));
+ config.setInt("input_autodetect_icade_profile_pad2", Integer
+ .valueOf(prefs.getString("input_autodetect_icade_profile_pad2",
+ "0")));
+ config.setInt("input_autodetect_icade_profile_pad3", Integer
+ .valueOf(prefs.getString("input_autodetect_icade_profile_pad3",
+ "0")));
+ config.setInt("input_autodetect_icade_profile_pad4", Integer
+ .valueOf(prefs.getString("input_autodetect_icade_profile_pad4",
+ "0")));
+
+ config.setDouble("video_refresh_rate",
+ getRefreshRate());
+ config.setBoolean("video_threaded",
+ prefs.getBoolean("video_threaded", true));
+
+ // Refactor these weird values - 'full', 'auto', 'square', whatever -
+ // go by what we have in RGUI - makes maintaining state easier too
+ String aspect = prefs.getString("video_aspect_ratio", "auto");
+ if (aspect.equals("full")) {
+ config.setBoolean("video_force_aspect", false);
+ } else if (aspect.equals("auto")) {
+ config.setBoolean("video_force_aspect", true);
+ config.setBoolean("video_force_aspect_auto", true);
+ config.setDouble("video_aspect_ratio", -1.0);
+ } else if (aspect.equals("square")) {
+ config.setBoolean("video_force_aspect", true);
+ config.setBoolean("video_force_aspect_auto", false);
+ config.setDouble("video_aspect_ratio", -1.0);
+ } else {
+ double aspect_ratio = Double.parseDouble(aspect);
+ config.setBoolean("video_force_aspect", true);
+ config.setDouble("video_aspect_ratio", aspect_ratio);
+ }
+
+ config.setBoolean("video_scale_integer",
+ prefs.getBoolean("video_scale_integer", false));
+
+ String shaderPath = prefs.getString("video_shader", "");
+ config.setString("video_shader", shaderPath);
+ config.setBoolean("video_shader_enable",
+ prefs.getBoolean("video_shader_enable", false)
+ && new File(shaderPath).exists());
+
+ boolean useOverlay = prefs.getBoolean("input_overlay_enable", true);
+ config.setBoolean("input_overlay_enable", useOverlay); // Not used by RetroArch directly.
+ if (useOverlay) {
+ String overlayPath = prefs
+ .getString("input_overlay", (getInstance()
+ .getApplicationInfo().dataDir)
+ + "/overlays/snes-landscape.cfg");
+ config.setString("input_overlay", overlayPath);
+ config.setDouble("input_overlay_opacity",
+ prefs.getFloat("input_overlay_opacity", 1.0f));
+ } else {
+ config.setString("input_overlay", "");
+ }
+ config.setString(
+ "savefile_directory",
+ prefs.getBoolean("savefile_directory_enable", false) ? prefs
+ .getString("savefile_directory", "") : "");
+ config.setString(
+ "savestate_directory",
+ prefs.getBoolean("savestate_directory_enable", false) ? prefs
+ .getString("savestate_directory", "") : "");
+ config.setString(
+ "system_directory",
+ prefs.getBoolean("system_directory_enable", false) ? prefs
+ .getString("system_directory", "") : "");
+
+ config.setBoolean("video_font_enable",
+ prefs.getBoolean("video_font_enable", true));
+
+ config.setString("game_history_path", getInstance()
+ .getApplicationInfo().dataDir + "/retroarch-history.txt");
+
+ for (int i = 1; i <= 4; i++) {
+ final String btns[] = { "up", "down", "left", "right", "a", "b",
+ "x", "y", "start", "select", "l", "r", "l2", "r2", "l3",
+ "r3" };
+ for (String b : btns) {
+ String p = "input_player" + String.valueOf(i) + "_" + b
+ + "_btn";
+ config.setInt(p, prefs.getInt(p, 0));
+ }
+ }
+
+ try {
+ config.write(new File(path));
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to save config file to: " + path);
+ }
+ }
+
private byte[] loadAsset(String asset) throws IOException {
String path = asset;
InputStream stream = getAssets().open(path);
@@ -74,22 +500,24 @@ public class MainMenuActivity extends PreferenceActivity {
stream.read(buf, 0, len);
return buf;
}
-
- private void extractAssets(AssetManager manager, String dataDir, String relativePath, int level) throws IOException {
+
+ private void extractAssets(AssetManager manager, String dataDir,
+ String relativePath, int level) throws IOException {
final String[] paths = manager.list(relativePath);
if (paths != null && paths.length > 0) { // Directory
- //Log.d(TAG, "Extracting assets directory: " + relativePath);
+ // Log.d(TAG, "Extracting assets directory: " + relativePath);
for (final String path : paths)
- extractAssets(manager, dataDir, relativePath + (level > 0 ? File.separator : "") + path, level + 1);
+ extractAssets(manager, dataDir, relativePath
+ + (level > 0 ? File.separator : "") + path, level + 1);
} else { // File, extract.
- //Log.d(TAG, "Extracting assets file: " + relativePath);
-
+ // Log.d(TAG, "Extracting assets file: " + relativePath);
+
String parentPath = new File(relativePath).getParent();
if (parentPath != null) {
File parentFile = new File(dataDir, parentPath);
parentFile.mkdirs(); // Doesn't throw.
}
-
+
byte[] asset = loadAsset(relativePath);
BufferedOutputStream writer = new BufferedOutputStream(
new FileOutputStream(new File(dataDir, relativePath)));
@@ -99,130 +527,337 @@ public class MainMenuActivity extends PreferenceActivity {
writer.close();
}
}
-
- private void extractAssets() {
+
+ private int getVersionCode() {
int version = 0;
try {
version = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode;
- } catch(NameNotFoundException e) {
- // weird exception, shouldn't happen
+ } catch (NameNotFoundException e) {
}
-
+
+ return version;
+ }
+
+ private boolean areAssetsExtracted() {
+ int version = getVersionCode();
+
try {
- AssetManager assets = getAssets();
String dataDir = getApplicationInfo().dataDir;
File cacheVersion = new File(dataDir, ".cacheversion");
- if (cacheVersion != null && cacheVersion.isFile() && cacheVersion.canRead() && cacheVersion.canWrite())
- {
- DataInputStream cacheStream = new DataInputStream(new FileInputStream(cacheVersion));
+ if (cacheVersion != null && cacheVersion.isFile()
+ && cacheVersion.canRead() && cacheVersion.canWrite()) {
+ DataInputStream cacheStream = new DataInputStream(
+ new FileInputStream(cacheVersion));
int currentCacheVersion = 0;
try {
currentCacheVersion = cacheStream.readInt();
- } catch (IOException e) {}
- cacheStream.close();
-
- if (currentCacheVersion == version)
- {
+ } catch (IOException e) {
+ }
+ cacheStream.close();
+
+ if (currentCacheVersion == version) {
Log.i("ASSETS", "Assets already extracted, skipping...");
- return;
+ return true;
}
}
-
- //extractAssets(assets, cacheDir, "", 0);
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to extract assets to cache.");
+ return false;
+ }
+
+ return false;
+ }
+
+ private void extractAssetsThread() {
+ try {
+ AssetManager assets = getAssets();
+ String dataDir = getApplicationInfo().dataDir;
+ File cacheVersion = new File(dataDir, ".cacheversion");
+
+ // extractAssets(assets, cacheDir, "", 0);
Log.i("ASSETS", "Extracting shader assets now ...");
try {
extractAssets(assets, dataDir, "shaders_glsl", 1);
} catch (IOException e) {
Log.i("ASSETS", "Failed to extract shaders ...");
}
-
+
Log.i("ASSETS", "Extracting overlay assets now ...");
try {
extractAssets(assets, dataDir, "overlays", 1);
} catch (IOException e) {
Log.i("ASSETS", "Failed to extract overlays ...");
}
-
- DataOutputStream outputCacheVersion = new DataOutputStream(new FileOutputStream(cacheVersion, false));
- outputCacheVersion.writeInt(version);
+
+ DataOutputStream outputCacheVersion = new DataOutputStream(
+ new FileOutputStream(cacheVersion, false));
+ outputCacheVersion.writeInt(getVersionCode());
outputCacheVersion.close();
} catch (IOException e) {
- Log.e(TAG, "Failed to extract assets to cache.");
+ Log.e(TAG, "Failed to extract assets to cache.");
}
}
+
+ private void extractAssets() {
+ if (areAssetsExtracted())
+ return;
+
+ final Dialog dialog = new Dialog(this);
+ final Handler handler = new Handler();
+ dialog.setContentView(R.layout.assets);
+ dialog.setCancelable(false);
+ dialog.setTitle("Asset extraction");
+
+ // Java is fun :)
+ Thread assetsThread = new Thread(new Runnable() {
+ public void run() {
+ extractAssetsThread();
+ handler.post(new Runnable() {
+ public void run() {
+ dialog.dismiss();
+ }
+ });
+ }
+ });
+ assetsThread.start();
+
+ dialog.show();
+ }
- boolean detectDevice(boolean show_dialog)
- {
+ public static SharedPreferences getPreferences() {
+ return PreferenceManager.getDefaultSharedPreferences(getInstance().getBaseContext());
+ }
+
+ public void setModule(String core_path, String core_name) {
+ updateConfigFile();
+
+ libretro_path = core_path;
+ libretro_name = core_name;
+
+ SharedPreferences prefs = getPreferences();
+ SharedPreferences.Editor edit = prefs.edit();
+ edit.putString("libretro_path", libretro_path);
+ edit.putString("libretro_name", libretro_name);
+ edit.commit();
+
+ if (usePerCoreConfig())
+ refreshPreferenceScreen();
+ else {
+ setCoreTitle(libretro_name); // this still needs to be applied
+ }
+ }
+
+ public void setCoreTitle(String core_name) {
+ setTitle("RetroArch : " + core_name);
+ }
+
+ boolean detectDevice(boolean show_dialog) {
boolean retval = false;
-
+
+ boolean mentionPlayStore = !android.os.Build.MODEL
+ .equals("OUYA Console");
+ final String message = "The ideal configuration options for your device will now be preconfigured.\n\nNOTE: For optimal performance, turn off Google Account sync, "
+ + (mentionPlayStore ? "Google Play Store auto-updates, " : "")
+ + "GPS and Wi-Fi in your Android settings menu.";
+
Log.i("Device MODEL", android.os.Build.MODEL);
- if (android.os.Build.MODEL.equals("SHIELD"))
- {
+ if (android.os.Build.MODEL.equals("SHIELD")) {
AlertDialog.Builder alert = new AlertDialog.Builder(this)
- .setTitle("NVidia Shield detected")
- .setMessage("The ideal configuration options for your device will now be preconfigured.\nNOTE: For optimal performance, turn off Google Account sync, Google Play Store auto-updates, GPS and Wifi in your Android settings menu.")
- .setPositiveButton("OK", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
- SharedPreferences.Editor edit = prefs.edit();
- edit.putString("video_refresh_rate", Double.valueOf(60.00d).toString());
- edit.putBoolean("input_overlay_enable", false);
- edit.putBoolean("input_autodetect_enable", true);
- edit.commit();
- }
- });
+ .setTitle("NVidia Shield detected")
+ .setMessage(message)
+ .setPositiveButton("OK",
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog,
+ int which) {
+ SharedPreferences prefs = getPreferences();
+ SharedPreferences.Editor edit = prefs
+ .edit();
+ edit.putString("video_refresh_rate", Double
+ .valueOf(60.00d).toString());
+ edit.putBoolean("input_overlay_enable",
+ false);
+ edit.putBoolean("input_autodetect_enable",
+ true);
+ edit.putString("audio_latency", "64");
+ edit.putBoolean("audio_latency_auto", true);
+ edit.commit();
+ }
+ });
+ alert.show();
+ retval = true;
+ } else if (android.os.Build.MODEL.equals("GAMEMID_BT")) {
+ AlertDialog.Builder alert = new AlertDialog.Builder(this)
+ .setTitle("GameMID detected")
+ .setMessage(message)
+ .setPositiveButton("OK",
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog,
+ int which) {
+ SharedPreferences prefs = getPreferences();
+ SharedPreferences.Editor edit = prefs
+ .edit();
+ edit.putBoolean("input_overlay_enable",
+ false);
+ edit.putBoolean("input_autodetect_enable",
+ true);
+ edit.putString("audio_latency", "160");
+ edit.putBoolean("audio_latency_auto", false);
+ edit.commit();
+ }
+ });
+ alert.show();
+ retval = true;
+ } else if (android.os.Build.MODEL.equals("OUYA Console")) {
+ AlertDialog.Builder alert = new AlertDialog.Builder(this)
+ .setTitle("OUYA detected")
+ .setMessage(message)
+ .setPositiveButton("OK",
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog,
+ int which) {
+ SharedPreferences prefs = getPreferences();
+ SharedPreferences.Editor edit = prefs
+ .edit();
+ edit.putBoolean("input_overlay_enable",
+ false);
+ edit.putBoolean("input_autodetect_enable",
+ true);
+ edit.putString("audio_latency", "64");
+ edit.putBoolean("audio_latency_auto", true);
+ edit.commit();
+ }
+ });
+ alert.show();
+ retval = true;
+ } else if (android.os.Build.MODEL.equals("R800x")) {
+ AlertDialog.Builder alert = new AlertDialog.Builder(this)
+ .setTitle("Xperia Play detected")
+ .setMessage(message)
+ .setPositiveButton("OK",
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog,
+ int which) {
+ SharedPreferences prefs = getPreferences();
+ SharedPreferences.Editor edit = prefs
+ .edit();
+ edit.putBoolean("video_threaded", false);
+ edit.putBoolean("input_overlay_enable",
+ false);
+ edit.putBoolean("input_autodetect_enable",
+ true);
+ edit.putString("video_refresh_rate", Double
+ .valueOf(59.19132938771038).toString());
+ edit.putString("audio_latency", "128");
+ edit.putBoolean("audio_latency_auto", false);
+ edit.commit();
+ }
+ });
+ alert.show();
+ retval = true;
+ } else if (android.os.Build.ID.equals("JSS15J")) {
+ AlertDialog.Builder alert = new AlertDialog.Builder(this)
+ .setTitle("Nexus 7 2013 detected")
+ .setMessage(message)
+ .setPositiveButton("OK",
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog,
+ int which) {
+ SharedPreferences prefs = getPreferences();
+ SharedPreferences.Editor edit = prefs
+ .edit();
+ edit.putString("video_refresh_rate", Double
+ .valueOf(59.65).toString());
+ edit.putString("audio_latency", "64");
+ edit.putBoolean("audio_latency_auto", false);
+ edit.commit();
+ }
+ });
alert.show();
retval = true;
}
- else if (android.os.Build.MODEL.equals( "OUYA Console"))
- {
- AlertDialog.Builder alert = new AlertDialog.Builder(this)
- .setTitle("OUYA detected")
- .setMessage("The ideal configuration options for your device will now be preconfigured.\nNOTE: For optimal performance, turn off Google Account sync, GPS and Wifi in your Android settings menu.")
- .setPositiveButton("OK", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
- SharedPreferences.Editor edit = prefs.edit();
- edit.putBoolean("input_overlay_enable", false);
- edit.putBoolean("input_autodetect_enable", true);
- edit.commit();
- }
- });
- alert.show();
- retval = true;
- }
- else if (android.os.Build.ID.equals("JSS15J"))
- {
- AlertDialog.Builder alert = new AlertDialog.Builder(this)
- .setTitle("Nexus 7 2013 detected")
- .setMessage("The ideal configuration options for your device will now be preconfigured.\nNOTE: For optimal performance, turn off Google Account sync, Google Play Store auto-updates, GPS and Wifi in your Android settings menu.")
- .setPositiveButton("OK", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
- SharedPreferences.Editor edit = prefs.edit();
- edit.putString("video_refresh_rate", Double.valueOf(59.65).toString());
- edit.commit();
- }
- });
- alert.show();
- retval = true;
- }
-
+
if (show_dialog) {
- Toast.makeText(this,
- "Device either not detected in list or doesn't have any optimal settings in our database.",
- Toast.LENGTH_SHORT).show();
+ Toast.makeText(
+ this,
+ "Device either not detected in list or doesn't have any optimal settings in our database.",
+ Toast.LENGTH_SHORT).show();
}
+ refreshPreferenceScreen();
+
return retval;
}
-
+
@Override
protected void onStart() {
super.onStart();
}
+
+ @Override
+ public void startActivity(Intent intent) {
+ if (intent.getComponent().getClassName()
+ .equals("org.retroarch.browser.ROMActivity")) {
+ if (new File(libretro_path).isDirectory() == false) {
+ super.startActivityForResult(intent, ACTIVITY_LOAD_ROM);
+ } else {
+ Toast.makeText(this,
+ "Go to 'Load Core' and select a core first.",
+ Toast.LENGTH_SHORT).show();
+ }
+ } else {
+ super.startActivity(intent);
+ }
+ }
+
+ @Override
+ protected void onActivityResult(int reqCode, int resCode, Intent data) {
+ switch (reqCode) {
+ case ACTIVITY_LOAD_ROM: {
+ if (data.getStringExtra("PATH") != null) {
+ updateConfigFile();
+ Intent myIntent;
+ String current_ime = Settings.Secure.getString(
+ getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD);
+ Toast.makeText(this,
+ "Loading: [" + data.getStringExtra("PATH") + "]...",
+ Toast.LENGTH_SHORT).show();
+ myIntent = new Intent(this, RetroActivity.class);
+ myIntent.putExtra("ROM", data.getStringExtra("PATH"));
+ myIntent.putExtra("LIBRETRO", libretro_path);
+ myIntent.putExtra("CONFIGFILE",
+ getDefaultConfigPath());
+ myIntent.putExtra("IME", current_ime);
+ startActivity(myIntent);
+ }
+ }
+ break;
+ }
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle data) {
+ super.onSaveInstanceState(data);
+ data.putBoolean("romexec", true);
+ }
+
+ private void loadRomExternal(String rom, String core) {
+ updateConfigFile();
+ Intent myIntent = new Intent(this, RetroActivity.class);
+ String current_ime = Settings.Secure.getString(getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD);
+ Toast.makeText(this, "Loading: [" + rom + "]...", Toast.LENGTH_SHORT)
+ .show();
+ myIntent.putExtra("ROM", rom);
+ myIntent.putExtra("LIBRETRO", core);
+ myIntent.putExtra("CONFIGFILE", getDefaultConfigPath());
+ myIntent.putExtra("IME", current_ime);
+ startActivity(myIntent);
+ }
}
diff --git a/android/phoenix/src/org/retroarch/browser/ModuleWrapper.java b/android/phoenix/src/org/retroarch/browser/ModuleWrapper.java
index c741c28af5..f029edb0cc 100644
--- a/android/phoenix/src/org/retroarch/browser/ModuleWrapper.java
+++ b/android/phoenix/src/org/retroarch/browser/ModuleWrapper.java
@@ -28,6 +28,15 @@ class ModuleWrapper implements IconAdapterItem {
} else
return stripped;
}
+
+ @Override
+ public String getSubText() {
+ String stripped = file.getName().replace(".so", "") + "_system";
+ if (config.keyExists(stripped)) {
+ return config.getString(stripped);
+ } else
+ return null;
+ }
@Override
public int getIconResourceId() {
diff --git a/android/phoenix/src/org/retroarch/browser/PopupMenuAbstract.java b/android/phoenix/src/org/retroarch/browser/PopupMenuAbstract.java
deleted file mode 100644
index 5477a187d7..0000000000
--- a/android/phoenix/src/org/retroarch/browser/PopupMenuAbstract.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.retroarch.browser;
-
-import android.content.Context;
-import android.os.Build;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.View;
-
-class PopupMenuAbstract extends LazyPopupMenu
-{
- private LazyPopupMenu lazy;
-
- public PopupMenuAbstract(Context context, View anchor)
- {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
- {
- lazy = new HoneycombPopupMenu(context, anchor);
- }
- }
-
- @Override
- public Menu getMenu() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
- {
- return lazy.getMenu();
- }
- else
- {
- return null;
- }
- }
-
- @Override
- public MenuInflater getMenuInflater() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
- {
- return lazy.getMenuInflater();
- }
- else
- {
- return null;
- }
- }
-
- @Override
- public void setOnMenuItemClickListener(PopupMenuAbstract.OnMenuItemClickListener listener) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
- {
- lazy.setOnMenuItemClickListener(listener);
- }
- }
-
- @Override
- public void show() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
- {
- lazy.show();
- }
- }
-}
diff --git a/android/phoenix/src/org/retroarch/browser/ROMActivity.java b/android/phoenix/src/org/retroarch/browser/ROMActivity.java
index 060f0bb6b9..27a9e084b2 100644
--- a/android/phoenix/src/org/retroarch/browser/ROMActivity.java
+++ b/android/phoenix/src/org/retroarch/browser/ROMActivity.java
@@ -4,14 +4,13 @@ import java.io.File;
import android.content.SharedPreferences;
import android.os.Bundle;
-import android.preference.PreferenceManager;
public class ROMActivity extends DirectoryActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
- String startPath = prefs.getString("phoenix_rom_dir", "");
+ SharedPreferences prefs = MainMenuActivity.getPreferences();
+ String startPath = prefs.getString("rgui_browser_directory", "");
if (!startPath.isEmpty() && new File(startPath).exists())
super.setStartDirectory(startPath);
diff --git a/android/phoenix/src/org/retroarch/browser/ROMDirActivity.java b/android/phoenix/src/org/retroarch/browser/ROMDirActivity.java
index 105a8d3e31..c29dfc9722 100644
--- a/android/phoenix/src/org/retroarch/browser/ROMDirActivity.java
+++ b/android/phoenix/src/org/retroarch/browser/ROMDirActivity.java
@@ -5,7 +5,7 @@ import android.os.Bundle;
public class ROMDirActivity extends DirectoryActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
- super.setPathSettingKey("phoenix_rom_dir");
+ super.setPathSettingKey("rgui_browser_directory");
super.setIsDirectoryTarget(true);
super.onCreate(savedInstanceState);
}
diff --git a/android/phoenix/src/org/retroarch/browser/RefreshRateSetOS.java b/android/phoenix/src/org/retroarch/browser/RefreshRateSetOS.java
index b9479c80eb..cbef30d588 100644
--- a/android/phoenix/src/org/retroarch/browser/RefreshRateSetOS.java
+++ b/android/phoenix/src/org/retroarch/browser/RefreshRateSetOS.java
@@ -4,7 +4,6 @@ import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
-import android.preference.PreferenceManager;
import android.view.Display;
import android.view.WindowManager;
import android.widget.Toast;
@@ -18,7 +17,7 @@ public class RefreshRateSetOS extends Activity {
final WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
final Display display = wm.getDefaultDisplay();
double rate = display.getRefreshRate();
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
+ SharedPreferences prefs = MainMenuActivity.getPreferences();
SharedPreferences.Editor edit = prefs.edit();
edit.putString("video_refresh_rate", Double.valueOf(rate).toString());
edit.commit();
diff --git a/android/phoenix/src/org/retroarch/browser/ReportIME.java b/android/phoenix/src/org/retroarch/browser/ReportIME.java
index 1a85b393ee..c8f5d463b4 100644
--- a/android/phoenix/src/org/retroarch/browser/ReportIME.java
+++ b/android/phoenix/src/org/retroarch/browser/ReportIME.java
@@ -2,6 +2,7 @@ package org.retroarch.browser;
import android.app.Activity;
import android.app.AlertDialog;
+import android.content.DialogInterface;
import android.os.Bundle;
import android.provider.Settings;
@@ -9,7 +10,27 @@ public class ReportIME extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- String current_ime = Settings.Secure.getString(getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
- new AlertDialog.Builder(this).setMessage(current_ime).setNeutralButton("Close", null).show();
+ String current_ime = Settings.Secure.getString(getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD);
+
+ final Activity ctx = this;
+ AlertDialog.Builder dialog = new AlertDialog.Builder(this)
+ .setMessage(current_ime)
+ .setNeutralButton("Close",
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog,
+ int which) {
+ ctx.finish();
+ }
+ }).setCancelable(true)
+ .setOnCancelListener(new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ ctx.finish();
+ }
+ });
+
+ dialog.show();
}
}
diff --git a/android/phoenix/src/org/retroarch/browser/RetroTVMode.java b/android/phoenix/src/org/retroarch/browser/RetroTVMode.java
new file mode 100644
index 0000000000..60e84b9998
--- /dev/null
+++ b/android/phoenix/src/org/retroarch/browser/RetroTVMode.java
@@ -0,0 +1,25 @@
+package org.retroarch.browser;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.provider.Settings;
+
+public class RetroTVMode extends Activity {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ MainMenuActivity.getInstance().updateConfigFile();
+
+ Intent myIntent = new Intent(this, RetroActivity.class);
+ String current_ime = Settings.Secure.getString(getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
+ myIntent.putExtra("CONFIGFILE", MainMenuActivity.getDefaultConfigPath());
+ myIntent.putExtra("IME", current_ime);
+ startActivity(myIntent);
+ finish();
+ }
+}
+
+
diff --git a/apple/OSX/en.lproj/InputBinder.xib b/apple/OSX/en.lproj/InputBinder.xib
new file mode 100644
index 0000000000..1dc324d900
--- /dev/null
+++ b/apple/OSX/en.lproj/InputBinder.xib
@@ -0,0 +1,384 @@
+
+
+
+ 1080
+ 12E55
+ 3084
+ 1187.39
+ 626.00
+
+
+ IBNSLayoutConstraint
+ NSButton
+ NSButtonCell
+ NSCustomObject
+ NSTextField
+ NSTextFieldCell
+ NSView
+ NSWindowTemplate
+
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+
+
+
+
+
+
+
+
+
+
+
+ window
+
+
+
+ 3
+
+
+
+ goAway:
+
+
+
+ 20
+
+
+
+
+
+ 0
+
+
+
+
+
+ -2
+
+
+ File's Owner
+
+
+ -1
+
+
+ First Responder
+
+
+ -3
+
+
+ Application
+
+
+ 1
+
+
+
+
+
+
+
+ 2
+
+
+
+
+ 4
+ 0
+
+ 4
+ 1
+
+ 20
+
+ 1000
+
+ 8
+ 29
+ 3
+
+
+
+ 6
+ 0
+
+ 6
+ 1
+
+ 20
+
+ 1000
+
+ 8
+ 29
+ 3
+
+
+
+ 3
+ 0
+
+ 3
+ 1
+
+ 20
+
+ 1000
+
+ 8
+ 29
+ 3
+
+
+
+ 6
+ 0
+
+ 6
+ 1
+
+ 20
+
+ 1000
+
+ 8
+ 29
+ 3
+
+
+
+ 5
+ 0
+
+ 5
+ 1
+
+ 20
+
+ 1000
+
+ 8
+ 29
+ 3
+
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+ 5
+
+
+
+
+ 9
+
+
+
+
+ 10
+
+
+
+
+ 11
+
+
+
+
+ 12
+
+
+
+
+
+
+
+ 13
+
+
+
+
+ 14
+
+
+
+
+ 15
+
+
+
+
+
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ {{357, 418}, {480, 270}}
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+
+
+
+
+
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+
+
+
+
+ 20
+
+
+
+
+ NSLayoutConstraint
+ NSObject
+
+ IBProjectSource
+ ./Classes/NSLayoutConstraint.h
+
+
+
+ RAInputBinder
+ NSWindow
+
+ IBProjectSource
+ ./Classes/RAInputBinder.h
+
+
+
+
+ 0
+ IBCocoaFramework
+ YES
+ 3
+ YES
+
+
diff --git a/apple/OSX/en.lproj/MainMenu.xib b/apple/OSX/en.lproj/MainMenu.xib
index 4ebd04b3f9..908154abc8 100644
--- a/apple/OSX/en.lproj/MainMenu.xib
+++ b/apple/OSX/en.lproj/MainMenu.xib
@@ -2,9 +2,9 @@
1080
- 12D78
+ 12E55
3084
- 1187.37
+ 1187.39
626.00
com.apple.InterfaceBuilder.CocoaPlugin
@@ -297,6 +297,28 @@
+
+
+ 585
+
+
+
+
+
+
+
+ 586
+
+
+
+
+
+
+
+ 587
+
+
+
@@ -1417,6 +1462,9 @@
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
@@ -1428,7 +1476,7 @@
- 584
+ 588
@@ -1443,6 +1491,39 @@
RetroArch_OSX
NSObject
+
+ id
+ id
+ id
+
+
+
+ coreWasChosen:
+ id
+
+
+ showCoresDirectory:
+ id
+
+
+ showPreferences:
+ id
+
+
+
+ NSWindow
+ NSWindow
+
+
+
+ _coreSelectSheet
+ NSWindow
+
+
+ window
+ NSWindow
+
+
IBProjectSource
./Classes/RetroArch_OSX.h
diff --git a/apple/OSX/Settings.xib b/apple/OSX/en.lproj/Settings.xib
similarity index 52%
rename from apple/OSX/Settings.xib
rename to apple/OSX/en.lproj/Settings.xib
index 1d5c744237..03a3147273 100644
--- a/apple/OSX/Settings.xib
+++ b/apple/OSX/en.lproj/Settings.xib
@@ -2,9 +2,9 @@
1080
- 12D78
+ 12E55
3084
- 1187.37
+ 1187.39
626.00
com.apple.InterfaceBuilder.CocoaPlugin
@@ -36,7 +36,7 @@
- NSObject
+ NSWindowController
FirstResponder
@@ -45,11 +45,11 @@
NSApplication
- 15
+ 3
2
- {{196, 240}, {671, 597}}
+ {{196, 240}, {759, 597}}
544735232
- Window
+ RetroArch Settings
NSWindow
@@ -69,10 +69,10 @@
256
- {148, 514}
+ {148, 555}
-
+
_NS:13
YES
NO
@@ -164,7 +164,7 @@
MC41AA
- 17
+ 30
104857600
@@ -176,7 +176,7 @@
1
- {{1, 1}, {148, 514}}
+ {{1, 1}, {148, 555}}
@@ -213,7 +213,7 @@
0.99404761904761907
- {{20, 61}, {150, 516}}
+ {{20, 20}, {150, 557}}
@@ -222,35 +222,11 @@
- QSAAAEEgAABBmAAAQZgAAA
+ QSAAAEEgAABCAAAAQgAAAA
0.25
4
1
-
-
- 268
- {{582, 13}, {75, 32}}
-
-
- _NS:9
- YES
-
- 67108864
- 134217728
- Close
-
- _NS:9
-
- -2038284288
- 129
-
-
- 200
- 25
-
- NO
-
268
@@ -263,7 +239,7 @@
256
- {471, 498}
+ {559, 539}
@@ -272,25 +248,27 @@
NO
YES
-
-
+
+
-2147483392
{{224, 0}, {16, 17}}
+
+
_NS:18
title
- 101
+ 276
16
1000
accessory
- 364
+ 277
40
1000
- {{1, 17}, {471, 498}}
+ {{1, 17}, {559, 539}}
@@ -383,29 +362,29 @@
NO
_doScroller:
- 0.99799599198396793
+ 0.9721706864564007
-2147483392
- {{1, 499}, {471, 16}}
+ {{1, 541}, {486, 15}}
-
+
_NS:60
NO
1
_doScroller:
- 0.82055749128919864
+ 0.55290102389078499
-
+
2304
- {{1, 0}, {471, 17}}
+ {{1, 0}, {559, 17}}
@@ -413,24 +392,26 @@
4
+
- {{178, 61}, {473, 516}}
+ {{178, 20}, {561, 557}}
-
+
_NS:9
133682
-
- QSAAAEEgAABBmAAAQZgAAA
+
+
+ QSAAAEEgAABCAAAAQgAAAA
0.25
4
1
- {671, 597}
+ {759, 597}
@@ -445,6 +426,22 @@
+
+
+ window
+
+
+
+ 422
+
+
+
+ delegate
+
+
+
+ 356
+
dataSource
@@ -477,14 +474,6 @@
104
-
-
- close:
-
-
-
- 122
-
_outline
@@ -493,45 +482,6 @@
180
-
-
- textField
-
-
- 274
-
-
-
- 266
- {145, 17}
-
-
- {250, 750}
- YES
-
- 67108928
- 272631808
- Table View Cell
-
-
-
- 6
- System
- controlColor
-
-
-
-
- NO
-
-
- {{1, 1}, {145, 17}}
-
-
-
-
- 108
-
dataSource
@@ -558,7 +508,7 @@
266
- {101, 17}
+ {{0, 7}, {276, 17}}
{250, 750}
@@ -566,22 +516,43 @@
67108928
272631808
- Table View Cell
+
-
+
+ 6
+ System
+ controlColor
+
+
NO
- {{1, 1}, {101, 17}}
+ {{1, 1}, {276, 30}}
168
+
+
+ value: stringValue
+
+
+
+
+
+ value: stringValue
+ value
+ stringValue
+ 2
+
+
+ 319
+
textField
@@ -592,15 +563,15 @@
266
- {364, 17}
+ {{0, 7}, {277, 17}}
-
+
{250, 750}
YES
- 67108928
- 272631808
- Table View Cell
+ 337641537
+ 272631872
+ String
@@ -609,13 +580,339 @@
NO
- {{105, 1}, {364, 17}}
+ {{280, 1}, {277, 30}}
172
+
+
+ value: stringValue
+
+
+
+
+
+ value: stringValue
+ value
+ stringValue
+ 2
+
+
+ 240
+
+
+
+ textField
+
+
+ 274
+
+
+
+ 266
+ {{0, 7}, {277, 17}}
+
+
+ {250, 750}
+ YES
+
+ 337641537
+ 272631872
+ Int
+
+
+
+
+
+ NO
+
+
+ {{280, 65}, {277, 30}}
+
+
+
+
+ 227
+
+
+
+ value: numericValue
+
+
+
+
+
+ value: numericValue
+ value
+ numericValue
+ 2
+
+
+ 241
+
+
+
+ value: booleanValue
+
+
+ 268
+ {{1, 6}, {61, 18}}
+
+
+ _NS:9
+ YES
+
+ -2080374784
+ 268435456
+
+
+ _NS:9
+
+ 1211912448
+ 2
+
+ NSImage
+ NSSwitch
+
+
+ NSSwitch
+
+
+
+ 200
+ 25
+
+ NO
+
+
+
+ 274
+
+
+
+ {{280, 33}, {277, 30}}
+
+
+
+
+
+ value: booleanValue
+ value
+ booleanValue
+ 2
+
+
+ 255
+
+
+
+ textField
+
+
+ 274
+
+
+
+ 266
+ {{0, 7}, {233, 17}}
+
+
+ {250, 750}
+ YES
+
+ 337641537
+ 272631872
+
+
+
+
+
+
+ NO
+
+
+
+ 268
+ {{232, -2}, {48, 32}}
+
+
+ _NS:9
+ YES
+
+ 67108864
+ 134217728
+ ...
+
+ _NS:9
+
+ -2038284288
+ 129
+
+
+ 200
+ 25
+
+ NO
+
+
+ {{280, 97}, {277, 30}}
+
+
+
+
+ 298
+
+
+
+ doBrowse:
+
+
+
+ 312
+
+
+
+ value: stringValue
+
+
+
+
+
+ value: stringValue
+ value
+ stringValue
+ 2
+
+
+ 314
+
+
+
+ textField
+
+
+ 274
+
+
+
+ 266
+ {{0, 7}, {145, 17}}
+
+
+ {250, 750}
+ YES
+
+ 67108928
+ 272631808
+
+
+
+
+
+
+ NO
+
+
+ {{1, 1}, {145, 30}}
+
+
+
+
+ 326
+
+
+
+ value: stringValue
+
+
+
+
+
+ value: stringValue
+ value
+ stringValue
+ 2
+
+
+ 327
+
+
+
+ doGetBind:
+
+
+ 274
+
+
+
+ 268
+ {{232, -2}, {48, 32}}
+
+
+ _NS:9
+ YES
+
+ 67108864
+ 134217728
+ ...
+
+ _NS:9
+
+ -2038284288
+ 129
+
+
+ 200
+ 25
+
+ NO
+
+
+
+ 266
+ {{0, 7}, {233, 17}}
+
+
+ {250, 750}
+ YES
+
+ 67108928
+ 272631872
+
+
+
+
+
+
+ NO
+
+
+ {{280, 129}, {277, 30}}
+
+
+
+
+ 564
+
+
+
+ value: stringValue
+
+
+
+
+
+ value: stringValue
+ value
+ stringValue
+ 2
+
+
+ 578
+
@@ -655,30 +952,12 @@
2
-
-
-
-
- 6
- 0
-
- 6
- 1
-
- 20
-
- 1000
-
- 8
- 29
- 3
-
4
0
-
+
4
1
@@ -690,39 +969,7 @@
29
3
-
-
- 3
- 0
-
- 4
- 1
-
- 20
-
- 1000
-
- 6
- 24
- 3
-
-
-
- 4
- 0
-
- 4
- 1
-
- 0.0
-
- 1000
-
- 6
- 24
- 2
-
-
+
6
0
@@ -738,6 +985,22 @@
29
3
+
+
+ 5
+ 0
+
+ 6
+ 1
+
+ 8
+
+ 1000
+
+ 6
+ 24
+ 3
+
5
@@ -770,28 +1033,12 @@
29
3
-
-
- 5
+
+
+ 4
0
- 6
- 1
-
- 8
-
- 1000
-
- 6
- 24
- 3
-
-
-
- 3
- 0
-
- 3
+ 4
1
20
@@ -818,6 +1065,23 @@
29
3
+
+
+ 3
+ 0
+
+ 3
+ 1
+
+ 20
+
+ 1000
+
+ 8
+ 29
+ 3
+
+
@@ -854,7 +1118,7 @@
-
+
@@ -868,88 +1132,6 @@
-
- 105
-
-
-
-
-
- 10
- 0
-
- 10
- 1
-
- 0.0
-
- 1000
-
- 5
- 22
- 2
-
-
-
- 6
- 0
-
- 6
- 1
-
- 3
-
- 1000
-
- 8
- 29
- 3
-
-
-
- 5
- 0
-
- 5
- 1
-
- 3
-
- 1000
-
- 8
- 29
- 3
-
-
-
-
-
- 106
-
-
-
-
-
-
-
- 107
-
-
-
-
- 116
-
-
-
-
-
-
-
- 117
-
-
-
148
@@ -989,20 +1171,6 @@
-
- 154
-
-
-
-
-
-
-
-
- 155
-
-
-
156
@@ -1013,23 +1181,23 @@
-
-
- 10
+
+
+ 6
0
-
- 10
+
+ 6
1
- 0.0
+ 3
1000
- 5
- 22
- 2
+ 8
+ 29
+ 3
-
+
5
0
@@ -1045,6 +1213,22 @@
29
3
+
+
+ 10
+ 0
+
+ 10
+ 1
+
+ 0.0
+
+ 1000
+
+ 5
+ 22
+ 2
+
@@ -1062,27 +1246,511 @@
- 169
-
+ 320
+
-
-
-
+
+
+ 10
+ 0
+
+ 10
+ 1
+
+ 0.0
+
+ 1000
+
+ 5
+ 22
+ 2
+
+
+
+ 5
+ 0
+
+ 5
+ 1
+
+ 3
+
+ 1000
+
+ 8
+ 29
+ 3
+
+
+
6
0
-
+
6
1
3
1000
-
+
8
29
3
-
+
+
+
+
+
+ 324
+
+
+
+
+
+
+
+ 325
+
+
+
+
+ 179
+
+
+
+
+ 353
+
+
+
+
+ 276
+
+
+
+
+ 272
+
+
+
+
+ 271
+
+
+
+
+ 267
+
+
+
+
+ 354
+
+
+
+
+ 273
+
+
+
+
+ 268
+
+
+
+
+ 317
+
+
+
+
+ 281
+
+
+
+
+ 280
+
+
+
+
+ 323
+
+
+
+
+ 322
+
+
+
+
+ 321
+
+
+
+
+ 154
+
+
+
+
+
+
+
+
+
+
+
+
+ 328
+
+
+
+
+ 5
+ 0
+
+ 6
+ 1
+
+ 8
+
+ 1000
+
+ 6
+ 24
+ 3
+
+
+
+ 6
+ 0
+
+ 6
+ 1
+
+ 3
+
+ 1000
+
+ 8
+ 29
+ 3
+
+
+
+ 10
+ 0
+
+ 10
+ 1
+
+ 0.0
+
+ 1000
+
+ 5
+ 22
+ 2
+
+
+
+ 5
+ 0
+
+ 5
+ 1
+
+ 3
+
+ 1000
+
+ 8
+ 29
+ 3
+
+
+
+ 10
+ 0
+
+ 10
+ 1
+
+ 0.0
+
+ 1000
+
+ 6
+ 24
+ 2
+
+
+
+
+
+
+
+ 335
+
+
+
+
+
+ 7
+ 0
+
+ 0
+ 1
+
+ 36
+
+ 1000
+
+ 3
+ 9
+ 1
+
+
+
+
+
+ 345
+
+
+
+
+ 336
+
+
+
+
+ 242
+
+
+
+
+
+ 10
+ 0
+
+ 10
+ 1
+
+ 0.0
+
+ 1000
+
+ 5
+ 22
+ 2
+
+
+
+ 5
+ 0
+
+ 5
+ 1
+
+ 3
+
+ 1000
+
+ 8
+ 29
+ 3
+
+
+
+
+
+ 249
+
+
+
+
+
+ 7
+ 0
+
+ 0
+ 1
+
+ 57
+
+ 1000
+
+ 3
+ 9
+ 1
+
+
+
+
+
+ 291
+
+
+
+
+ 290
+
+
+
+
+ 292
+
+
+
+
+ 250
+
+
+
+
+ 295
+
+
+
+
+ 5
+ 0
+
+ 6
+ 1
+
+ 8
+
+ 1000
+
+ 6
+ 24
+ 3
+
+
+
+ 6
+ 0
+
+ 6
+ 1
+
+ 3
+
+ 1000
+
+ 8
+ 29
+ 3
+
+
+
+ 10
+ 0
+
+ 10
+ 1
+
+ 0.0
+
+ 1000
+
+ 5
+ 22
+ 2
+
+
+
+ 10
+ 0
+
+ 10
+ 1
+
+ 0.0
+
+ 1000
+
+ 6
+ 24
+ 2
+
+
+
+ 5
+ 0
+
+ 5
+ 1
+
+ 3
+
+ 1000
+
+ 8
+ 29
+ 3
+
+
+
+
+
+
+
+ 296
+
+
+
+
+
+
+
+ 297
+
+
+
+
+ 303
+
+
+
+
+
+ 7
+ 0
+
+ 0
+ 1
+
+ 36
+
+ 1000
+
+ 3
+ 9
+ 1
+
+
+
+
+
+ 309
+
+
+
+
+ 304
+
+
+
+
+ 169
+
+
+
+
5
0
@@ -1098,7 +1766,7 @@
29
3
-
+
10
0
@@ -1114,6 +1782,22 @@
22
2
+
+
+ 6
+ 0
+
+ 6
+ 1
+
+ 3
+
+ 1000
+
+ 8
+ 29
+ 3
+
@@ -1125,105 +1809,177 @@
+
+ 289
+
+
+
+
+ 288
+
+
+
+
+ 287
+
+
+
171
- 179
-
-
+ 224
+
+
+
+
+
+ 6
+ 0
+
+ 6
+ 1
+
+ 3
+
+ 1000
+
+ 8
+ 29
+ 3
+
+
+
+ 10
+ 0
+
+ 10
+ 1
+
+ 0.0
+
+ 1000
+
+ 5
+ 22
+ 2
+
+
+
+ 5
+ 0
+
+ 5
+ 1
+
+ 3
+
+ 1000
+
+ 8
+ 29
+ 3
+
+
+
- 195
-
-
+ 225
+
+
+
+
+
- 196
-
-
+ 294
+
+
- 197
-
-
+ 293
+
+
- 198
-
-
+ 285
+
+
- 199
-
-
+ 226
+
+
- 200
-
-
+ 155
+
+
- 201
-
-
+ 311
+
+
- 202
-
-
+ 300
+
+
- 203
-
-
+ 476
+
+
- 204
-
-
+ 547
+
+
- 205
-
-
+ 548
+
+
- 206
-
-
+ 561
+
+
- 207
-
-
+ 565
+
+
+
+
+
- 208
-
-
+ 566
+
+
- 209
-
-
+ 574
+
+
- 210
-
-
+ 575
+
+
- 211
-
-
+ 576
+
+
- 212
-
-
+ 572
+
+
@@ -1234,18 +1990,6 @@
com.apple.InterfaceBuilder.CocoaPlugin
{{357, 418}, {480, 270}}
-
-
-
-
-
- com.apple.InterfaceBuilder.CocoaPlugin
-
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
-
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
@@ -1261,58 +2005,146 @@
+
+
+
+
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
+ RASettingCell
-
-
+
+
+
com.apple.InterfaceBuilder.CocoaPlugin
+ RALabelSetting
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
+ RASettingCell
-
-
-
+
+
+
com.apple.InterfaceBuilder.CocoaPlugin
+ RAStringSetting
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
-
+
+
-
-
+
-
-
-
+
+
-
com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
+ RASettingCell
+
+
+
+
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+ RANumericSetting
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ RASettingCell
+
+
+
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+ RABooleanSetting
+
+
+
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ RASettingCell
+
+
+
+
+
+
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+ RAPathSetting
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+
+
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ RASettingCell
+
+
+
+
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+ RALabelSetting
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ RASettingCell
+
+
+
+
+
+
+
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+ RABindSetting
+
+
+
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
@@ -1322,16 +2154,26 @@
com.apple.InterfaceBuilder.CocoaPlugin
-
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
- 212
+ 581
@@ -1344,25 +2186,37 @@
- RASettingsDelegate
- NSObject
-
- close:
- id
+ RASettingCell
+ NSTableCellView
+
+ numericValue
+ NSNumber
-
- close:
-
- close:
- id
+
+ numericValue
+
+ numericValue
+ NSNumber
+
+ IBProjectSource
+ ./Classes/RASettingCell.h
+
+
+
+ RASettingsDelegate
+ NSObject
+ NSWindow
NSOutlineView
NSTableView
- NSWindow
+
+ _inputWindow
+ NSWindow
+
_outline
NSOutlineView
@@ -1371,10 +2225,6 @@
_table
NSTableView
-
- _window
- NSWindow
-
IBProjectSource
@@ -1387,6 +2237,10 @@
IBCocoaFramework
YES
3
+
+ NSSwitch
+ {15, 15}
+
YES
diff --git a/apple/OSX/hid_pad.c b/apple/OSX/hid_pad.c
index 79c453e9b3..4d0b50eb66 100644
--- a/apple/OSX/hid_pad.c
+++ b/apple/OSX/hid_pad.c
@@ -14,27 +14,45 @@
*/
#include
-#include "../RetroArch/apple_input.h"
+#include "apple/common/apple_input.h"
+#include "apple/common/hidpad/hidpad.h"
-// NOTE: I pieced this together through trial and error, any corrections are welcome
+struct hidpad_connection
+{
+ uint32_t slot;
+
+ struct hidpad_interface* interface;
+ void* hidpad;
+
+ IOHIDDeviceRef device;
+
+ uint8_t data[2048];
+};
static IOHIDManagerRef g_hid_manager;
+static struct hidpad_connection g_connected_pads[MAX_PADS];
-static void hid_input_callback(void* inContext, IOReturn inResult, void* inSender, IOHIDValueRef inIOHIDValueRef)
+void hidpad_send_control(struct hidpad_connection* connection, uint8_t* data, size_t size)
{
- IOHIDElementRef element = IOHIDValueGetElement(inIOHIDValueRef);
- IOHIDDeviceRef device = IOHIDElementGetDevice(element);
+ IOHIDDeviceSetReport(connection->device, kIOHIDReportTypeOutput, 0x01, data, size);
+}
+// NOTE: I pieced this together through trial and error, any corrections are welcome
+static void hid_device_input_callback(void* context, IOReturn result, void* sender, IOHIDValueRef value)
+{
+ struct hidpad_connection* connection = context;
+
+ IOHIDElementRef element = IOHIDValueGetElement(value);
uint32_t type = IOHIDElementGetType(element);
uint32_t page = IOHIDElementGetUsagePage(element);
uint32_t use = IOHIDElementGetUsage(element);
// Mouse handler
- if (IOHIDDeviceConformsTo(device, kHIDPage_GenericDesktop, kHIDUsage_GD_Mouse))
+ if (!connection)
{
if (type == kIOHIDElementTypeInput_Button && page == kHIDPage_Button)
{
- CFIndex state = IOHIDValueGetIntegerValue(inIOHIDValueRef);
+ CFIndex state = IOHIDValueGetIntegerValue(value);
if (state) g_current_input_data.mouse_buttons |= (1 << (use - 1));
else g_current_input_data.mouse_buttons &= ~(1 << (use - 1));
@@ -45,22 +63,18 @@ static void hid_input_callback(void* inContext, IOReturn inResult, void* inSende
for (int i = 0; i < 2; i ++)
if (use == axis_use_ids[i])
- g_current_input_data.mouse_delta[i] += IOHIDValueGetIntegerValue(inIOHIDValueRef);
+ g_current_input_data.mouse_delta[i] += IOHIDValueGetIntegerValue(value);
}
}
- // Joystick handler
- else if (IOHIDDeviceConformsTo(device, kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick))
+ // Joystick handler: TODO: Can GamePad work the same?
+ else if (IOHIDDeviceConformsTo(connection->device, kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick))
{
- uint32_t slot = (uint32_t)inContext;
- if (slot >= 4)
- return;
-
if (type == kIOHIDElementTypeInput_Button && page == kHIDPage_Button)
{
- CFIndex state = IOHIDValueGetIntegerValue(inIOHIDValueRef);
+ CFIndex state = IOHIDValueGetIntegerValue(value);
- if (state) g_current_input_data.pad_buttons[slot] |= (1 << (use - 1));
- else g_current_input_data.pad_buttons[slot] &= ~(1 << (use - 1));
+ if (state) g_current_input_data.pad_buttons[connection->slot] |= (1 << (use - 1));
+ else g_current_input_data.pad_buttons[connection->slot] &= ~(1 << (use - 1));
}
else if (type == kIOHIDElementTypeInput_Misc && page == kHIDPage_GenericDesktop)
{
@@ -71,29 +85,94 @@ static void hid_input_callback(void* inContext, IOReturn inResult, void* inSende
{
CFIndex min = IOHIDElementGetPhysicalMin(element);
CFIndex max = IOHIDElementGetPhysicalMax(element) - min;
- CFIndex state = IOHIDValueGetIntegerValue(inIOHIDValueRef) - min;
+ CFIndex state = IOHIDValueGetIntegerValue(value) - min;
float val = (float)state / (float)max;
- g_current_input_data.pad_axis[slot][i] = ((val * 2.0f) - 1.0f) * 32767.0f;
+ g_current_input_data.pad_axis[connection->slot][i] = ((val * 2.0f) - 1.0f) * 32767.0f;
}
}
}
}
}
-static void hid_device_attached(void* inContext, IOReturn inResult, void* inSender, IOHIDDeviceRef inDevice)
+static void hid_device_removed(void* context, IOReturn result, void* sender)
{
- IOHIDDeviceOpen(inDevice, kIOHIDOptionsTypeNone);
- IOHIDDeviceScheduleWithRunLoop(inDevice, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
- IOHIDDeviceRegisterInputValueCallback(inDevice, hid_input_callback, 0);
+ struct hidpad_connection* connection = (struct hidpad_connection*)context;
+
+ if (connection && connection->slot < MAX_PADS)
+ {
+ g_current_input_data.pad_buttons[connection->slot] = 0;
+ memset(g_current_input_data.pad_axis[connection->slot], 0, sizeof(g_current_input_data.pad_axis));
+
+ if (connection->interface)
+ connection->interface->disconnect(connection->hidpad);
+ memset(connection, 0, sizeof(*connection));
+ }
+
+ IOHIDDeviceClose(sender, kIOHIDOptionsTypeNone);
}
-static void hid_device_removed(void* inContext, IOReturn inResult, void* inSender, IOHIDDeviceRef inDevice)
+static void hid_device_report(void* context, IOReturn result, void *sender, IOHIDReportType type, uint32_t reportID, uint8_t *report, CFIndex reportLength)
{
- IOHIDDeviceClose(inDevice, kIOHIDOptionsTypeNone);
+ struct hidpad_connection* connection = (struct hidpad_connection*)context;
+ connection->interface->packet_handler(connection->hidpad, report, reportLength);
}
-static CFMutableDictionaryRef build_matching_dictionary(uint32_t page, uint32_t use)
+static void hid_manager_device_attached(void* context, IOReturn result, void* sender, IOHIDDeviceRef device)
+{
+ bool is_pad = (IOHIDDeviceConformsTo(device, kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick) ||
+ IOHIDDeviceConformsTo(device, kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad));
+
+ struct hidpad_connection* connection = 0;
+
+ if (is_pad)
+ {
+ for (int i = 0; i != MAX_PADS; i ++)
+ {
+ if (!g_connected_pads[i].device)
+ {
+ connection = &g_connected_pads[i];
+ connection->device = device;
+ connection->slot = i;
+ break;
+ }
+ }
+
+ if (!connection)
+ return;
+ }
+
+ IOHIDDeviceOpen(device, kIOHIDOptionsTypeNone);
+ IOHIDDeviceScheduleWithRunLoop(device, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
+ IOHIDDeviceRegisterRemovalCallback(device, hid_device_removed, connection);
+
+ CFStringRef device_name = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
+ if (is_pad && device_name)
+ {
+ static const struct { const char* name; struct hidpad_interface* iface; } hidpad_map[] = {
+ { "Nintendo RVL-CNT-01", &hidpad_wii },
+ { "PLAYSTATION(R)3 Controller", &hidpad_ps3 },
+ { 0, 0} };
+
+ char buffer[1024];
+ CFStringGetCString(device_name, buffer, 1024, kCFStringEncodingUTF8);
+
+ for (int i = 0; hidpad_map[i].name; i ++)
+ {
+ if (strstr(buffer, hidpad_map[i].name))
+ {
+ connection->interface = hidpad_map[i].iface;
+ IOHIDDeviceRegisterInputReportCallback(device, connection->data, 2048, hid_device_report, connection);
+ connection->hidpad = connection->interface->connect(connection, connection->slot);
+ return;
+ }
+ }
+ }
+
+ IOHIDDeviceRegisterInputValueCallback(device, hid_device_input_callback, connection);
+}
+
+static void append_matching_dictionary(CFMutableArrayRef array, uint32_t page, uint32_t use)
{
CFMutableDictionaryRef matcher = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
@@ -105,7 +184,8 @@ static CFMutableDictionaryRef build_matching_dictionary(uint32_t page, uint32_t
CFDictionarySetValue(matcher, CFSTR(kIOHIDDeviceUsageKey), usen);
CFRelease(usen);
- return matcher;
+ CFArrayAppendValue(array, matcher);
+ CFRelease(matcher);
}
void osx_pad_init()
@@ -115,21 +195,15 @@ void osx_pad_init()
g_hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
CFMutableArrayRef matcher = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
-
- CFMutableDictionaryRef mouse = build_matching_dictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Mouse);
- CFArrayAppendValue(matcher, mouse);
- CFRelease(mouse);
-
- CFMutableDictionaryRef joystick = build_matching_dictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick);
- CFArrayAppendValue(matcher, joystick);
- CFRelease(joystick);
+ append_matching_dictionary(matcher, kHIDPage_GenericDesktop, kHIDUsage_GD_Mouse);
+ append_matching_dictionary(matcher, kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick);
+ append_matching_dictionary(matcher, kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad);
IOHIDManagerSetDeviceMatchingMultiple(g_hid_manager, matcher);
CFRelease(matcher);
- IOHIDManagerRegisterDeviceMatchingCallback(g_hid_manager, hid_device_attached, 0);
- IOHIDManagerRegisterDeviceRemovalCallback(g_hid_manager, hid_device_removed, 0);
- IOHIDManagerScheduleWithRunLoop(g_hid_manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+ IOHIDManagerRegisterDeviceMatchingCallback(g_hid_manager, hid_manager_device_attached, 0);
+ IOHIDManagerScheduleWithRunLoop(g_hid_manager, CFRunLoopGetMain(), kCFRunLoopCommonModes);
IOHIDManagerOpen(g_hid_manager, kIOHIDOptionsTypeNone);
}
@@ -140,7 +214,7 @@ void osx_pad_quit()
if (g_hid_manager)
{
IOHIDManagerClose(g_hid_manager, kIOHIDOptionsTypeNone);
- IOHIDManagerUnscheduleFromRunLoop(g_hid_manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+ IOHIDManagerUnscheduleFromRunLoop(g_hid_manager, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
CFRelease(g_hid_manager);
}
diff --git a/apple/OSX/platform.h b/apple/OSX/platform.h
new file mode 100644
index 0000000000..b01f6526f5
--- /dev/null
+++ b/apple/OSX/platform.h
@@ -0,0 +1,46 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2013 - Jason Fetters
+ * Copyright (C) 2011-2013 - Daniel De Matteis
+ *
+ * RetroArch is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with RetroArch.
+ * If not, see .
+ */
+
+#ifndef __RARCH_OSX_PLATFORM_H
+#define __RARCH_OSX_PLATFORM_H
+
+#import
+
+@interface RAGameView : NSView
+
++ (RAGameView*)get;
+- (void)display;
+
+@end
+
+@interface RetroArch_OSX : NSObject
+{
+@public
+ NSWindow IBOutlet *window;
+}
+
++ (RetroArch_OSX*)get;
+
+- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file;
+- (void)unloadingCore:(RAModuleInfo*)core;
+
+@property (strong, nonatomic) NSString* configDirectory; // e.g. /var/mobile/Documents/.RetroArch
+@property (strong, nonatomic) NSString* globalConfigFile; // e.g. /var/mobile/Documents/.RetroArch/retroarch.cfg
+@property (strong, nonatomic) NSString* coreDirectory; // e.g. /Applications/RetroArch.app/modules
+
+@end
+
+#endif
diff --git a/apple/OSX/platform.m b/apple/OSX/platform.m
new file mode 100644
index 0000000000..f911432227
--- /dev/null
+++ b/apple/OSX/platform.m
@@ -0,0 +1,249 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2013 - Jason Fetters
+ *
+ * RetroArch is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with RetroArch.
+ * If not, see .
+ */
+
+#include
+#include
+
+#import "RetroArch_Apple.h"
+#include "rarch_wrapper.h"
+#include "apple/common/apple_input.h"
+
+#include "file.h"
+
+@interface RApplication : NSApplication
+@end
+
+@implementation RApplication
+
+- (void)sendEvent:(NSEvent *)event
+{
+ [super sendEvent:event];
+
+ if (event.type == GSEVENT_TYPE_KEYDOWN || event.type == GSEVENT_TYPE_KEYUP)
+ apple_input_handle_key_event(event.keyCode, event.type == GSEVENT_TYPE_KEYDOWN);
+}
+
+@end
+
+@implementation RetroArch_OSX
+{
+ NSWindow IBOutlet* _coreSelectSheet;
+
+ bool _isTerminating;
+ bool _loaded;
+ bool _wantReload;
+ NSString* _file;
+ RAModuleInfo* _core;
+}
+
++ (RetroArch_OSX*)get
+{
+ return (RetroArch_OSX*)[[NSApplication sharedApplication] delegate];
+}
+
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
+{
+ apple_platform = self;
+ _loaded = true;
+
+ NSArray* paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
+ self.configDirectory = [paths[0] stringByAppendingPathComponent:@"RetroArch"];
+ self.globalConfigFile = [NSString stringWithFormat:@"%@/retroarch.cfg", self.configDirectory];
+ self.coreDirectory = [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"Contents/Resources/modules"];
+
+ [window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
+
+ RAGameView.get.frame = [window.contentView bounds];
+ [window.contentView setAutoresizesSubviews:YES];
+ [window.contentView addSubview:RAGameView.get];
+ [window makeFirstResponder:RAGameView.get];
+
+ // Create core select list
+ NSComboBox* cb = (NSComboBox*)[_coreSelectSheet.contentView viewWithTag:1];
+
+ for (RAModuleInfo* i in apple_get_modules())
+ [cb addItemWithObjectValue:i];
+
+ if (cb.numberOfItems)
+ [cb selectItemAtIndex:0];
+ else
+ apple_display_alert(@"No libretro cores were found.\nSelect \"Go->Cores Directory\" from the menu and place libretro dylib files there.", @"RetroArch");
+
+ // Run RGUI if needed
+ if (!_wantReload || apple_argv)
+ apple_run_core(nil, 0);
+ else
+ [self chooseCore];
+
+ _wantReload = false;
+
+ extern void osx_pad_init();
+ osx_pad_init();
+}
+
+- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
+{
+ return YES;
+}
+
+- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
+{
+ _isTerminating = true;
+
+ if (apple_is_running)
+ apple_frontend_post_event(apple_event_basic_command, (void*)QUIT);
+
+ return apple_is_running ? NSTerminateCancel : NSTerminateNow;
+}
+
+
+- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames
+{
+ if (filenames.count == 1 && filenames[0])
+ {
+ _file = filenames[0];
+
+ if (!_loaded)
+ _wantReload = true;
+ else
+ [self chooseCore];
+
+ [sender replyToOpenOrPrint:NSApplicationDelegateReplySuccess];
+ }
+ else
+ {
+ apple_display_alert(@"Cannot open multiple files", @"RetroArch");
+ [sender replyToOpenOrPrint:NSApplicationDelegateReplyFailure];
+ }
+}
+
+- (void)openDocument:(id)sender
+{
+ NSOpenPanel* panel = [NSOpenPanel openPanel];
+ [panel beginSheetModalForWindow:window completionHandler:^(NSInteger result)
+ {
+ [NSApplication.sharedApplication stopModal];
+
+ if (result == NSOKButton && panel.URL)
+ {
+ _file = panel.URL.path;
+ [self performSelector:@selector(chooseCore) withObject:nil afterDelay:.5f];
+ }
+ }];
+ [NSApplication.sharedApplication runModalForWindow:panel];
+}
+
+// This utility function will queue the _core and _file instance values for running.
+// If the emulator thread is already running it will tell it to quit.
+- (void)runCore
+{
+ _wantReload = apple_is_running;
+
+ if (!apple_is_running)
+ apple_run_core(_core, _file.UTF8String);
+ else
+ apple_frontend_post_event(apple_event_basic_command, (void*)QUIT);
+}
+
+- (void)chooseCore
+{
+ [NSApplication.sharedApplication beginSheet:_coreSelectSheet modalForWindow:window modalDelegate:nil didEndSelector:nil contextInfo:nil];
+ [NSApplication.sharedApplication runModalForWindow:_coreSelectSheet];
+}
+
+- (IBAction)coreWasChosen:(id)sender
+{
+ [NSApplication.sharedApplication stopModal];
+ [NSApplication.sharedApplication endSheet:_coreSelectSheet returnCode:0];
+ [_coreSelectSheet orderOut:self];
+
+ if (_isTerminating)
+ return;
+
+ NSComboBox* cb = (NSComboBox*)[_coreSelectSheet.contentView viewWithTag:1];
+ _core = (RAModuleInfo*)cb.objectValueOfSelectedItem;
+
+ [self runCore];
+}
+
+#pragma mark RetroArch_Platform
+- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file
+{
+ if (file)
+ [NSDocumentController.sharedDocumentController noteNewRecentDocumentURL:[NSURL fileURLWithPath:@(file)]];
+}
+
+- (void)unloadingCore:(RAModuleInfo*)core
+{
+ if (_isTerminating)
+ [NSApplication.sharedApplication terminate:nil];
+
+ if (_wantReload)
+ apple_run_core(_core, _file.UTF8String);
+ else if(apple_use_tv_mode)
+ apple_run_core(nil, 0);
+ else
+ [NSApplication.sharedApplication terminate:nil];
+
+ _wantReload = false;
+}
+
+#pragma mark Menus
+- (IBAction)showCoresDirectory:(id)sender
+{
+ [[NSWorkspace sharedWorkspace] openFile:self.coreDirectory];
+}
+
+- (IBAction)showPreferences:(id)sender
+{
+ NSWindowController* wc = [[NSWindowController alloc] initWithWindowNibName:@"Settings"];
+ [NSApp runModalForWindow:wc.window];
+}
+
+- (IBAction)basicEvent:(id)sender
+{
+ if (apple_is_running)
+ apple_frontend_post_event(&apple_event_basic_command, (void*)((NSMenuItem*)sender).tag);
+}
+
+- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
+{
+ [NSApplication.sharedApplication stopModal];
+}
+
+@end
+
+int main(int argc, char *argv[])
+{
+ uint32_t current_argc = 0;
+
+ for (int i = 0; i != argc; i ++)
+ {
+ if (strcmp(argv[i], "--") == 0)
+ {
+ current_argc = 1;
+ apple_argv = malloc(sizeof(char*) * (argc + 1));
+ memset(apple_argv, 0, sizeof(char*) * (argc + 1));
+ apple_argv[0] = argv[0];
+ }
+ else if (current_argc)
+ {
+ apple_argv[current_argc ++] = argv[i];
+ }
+ }
+
+ return NSApplicationMain(argc, (const char **) argv);
+}
+
diff --git a/apple/OSX/settings.m b/apple/OSX/settings.m
index 4bebfb07ec..51226fee4b 100644
--- a/apple/OSX/settings.m
+++ b/apple/OSX/settings.m
@@ -14,16 +14,268 @@
*/
#import
-#import "../RetroArch/RetroArch_Apple.h"
-#include "../RetroArch/setting_data.h"
+#import "apple/common/RetroArch_Apple.h"
+#include "apple/common/setting_data.h"
+#include "apple/common/apple_input.h"
+
+#include "driver.h"
+#include "input/input_common.h"
+
+struct settings fake_settings;
+struct global fake_extern;
+
+static const void* associated_name_tag = (void*)&associated_name_tag;
+
+#define BINDFOR(s) (*(struct retro_keybind*)(&s)->value)
+
+static const char* key_name_for_id(uint32_t hidkey)
+{
+ for (int i = 0; apple_key_name_map[i].hid_id; i ++)
+ if (apple_key_name_map[i].hid_id == hidkey)
+ return apple_key_name_map[i].keyname;
+
+ return "nul";
+}
+
+static uint32_t key_id_for_name(const char* name)
+{
+ for (int i = 0; apple_key_name_map[i].hid_id; i ++)
+ if (strcmp(name, apple_key_name_map[i].keyname) == 0)
+ return apple_key_name_map[i].hid_id;
+
+ return 0;
+}
+
+#define key_name_for_rk(X) key_name_for_id(input_translate_rk_to_keysym(X))
+#define key_rk_for_name(X) input_translate_keysym_to_rk(key_id_for_name(X))
+
+static const char* get_input_config_key(const rarch_setting_t* setting, const char* type)
+{
+ static char buffer[32];
+ if (setting->input_player)
+ snprintf(buffer, 32, "input_player%d_%s%c%s", setting->input_player, setting->name, type ? '_' : '\0', type);
+ else
+ snprintf(buffer, 32, "input_%s%c%s", setting->name, type ? '_' : '\0', type);
+ return buffer;
+}
+
+static const char* get_button_name(const rarch_setting_t* setting)
+{
+ static char buffer[32];
+
+ if (BINDFOR(*setting).joykey == NO_BTN)
+ return "nul";
+
+ snprintf(buffer, 32, "%lld", BINDFOR(*setting).joykey);
+ return buffer;
+}
+
+static const char* get_axis_name(const rarch_setting_t* setting)
+{
+ static char buffer[32];
+
+ uint32_t joyaxis = BINDFOR(*setting).joyaxis;
+
+ if (AXIS_NEG_GET(joyaxis) != AXIS_DIR_NONE)
+ snprintf(buffer, 8, "-%d", AXIS_NEG_GET(joyaxis));
+ else if (AXIS_POS_GET(joyaxis) != AXIS_DIR_NONE)
+ snprintf(buffer, 8, "+%d", AXIS_POS_GET(joyaxis));
+ else
+ return "nul";
+
+ return buffer;
+}
+
+@interface RANumberFormatter : NSNumberFormatter
+@end
+
+@implementation RANumberFormatter
+- (id)initWithFloatSupport:(bool)allowFloat minimum:(double)min maximum:(double)max
+{
+ self = [super init];
+ self.allowsFloats = allowFloat;
+ self.maximumFractionDigits = 10;
+
+ if (min || max)
+ {
+ self.minimum = @(min);
+ self.maximum = @(max);
+ }
+
+ return self;
+}
+
+- (BOOL)isPartialStringValid:(NSString*)partialString newEditingString:(NSString**)newString errorDescription:(NSString**)error
+{
+ bool hasDot = false;
+
+ if (partialString.length)
+ for (int i = 0; i != partialString.length; i ++)
+ {
+ unichar ch = [partialString characterAtIndex:i];
+
+ if (i == 0 && (!self.minimum || self.minimum.intValue < 0) && ch == '-')
+ continue;
+ else if (self.allowsFloats && !hasDot && ch == '.')
+ hasDot = true;
+ else if (!isdigit(ch))
+ return NO;
+ }
+
+ return YES;
+}
+@end
+
+
+@interface RAInputBinder : NSWindow
+@end
+
+@implementation RAInputBinder
+
+- (IBAction)goAway:(id)sender
+{
+ [NSApp endSheet:self];
+ [self orderOut:nil];
+}
+
+// Stop the annoying sound when pressing a key
+- (void)keyDown:(NSEvent*)theEvent
+{
+}
+
+@end
+
+@interface RASettingCell : NSTableCellView
+@property (nonatomic) const rarch_setting_t* setting;
+
+@property (nonatomic) NSString* stringValue;
+@property (nonatomic) IBOutlet NSNumber* numericValue;
+@property (nonatomic) bool booleanValue;
+
+@property (nonatomic) NSTimer* bindTimer;
+@end
+
+@implementation RASettingCell
+- (void)setSetting:(const rarch_setting_t *)aSetting
+{
+ _setting = aSetting;
+
+ if (!_setting)
+ return;
+
+ if (aSetting->type == ST_INT || aSetting->type == ST_FLOAT)
+ {
+ self.textField.formatter = [[RANumberFormatter alloc] initWithFloatSupport:aSetting->type == ST_FLOAT
+ minimum:aSetting->min
+ maximum:aSetting->max];
+ }
+ else
+ self.textField.formatter = nil;
+
+ // Set value
+ switch (aSetting->type)
+ {
+ case ST_INT: self.numericValue = @(*(int*)aSetting->value); break;
+ case ST_FLOAT: self.numericValue = @(*(float*)aSetting->value); break;
+ case ST_STRING: self.stringValue = @((const char*)aSetting->value); break;
+ case ST_PATH: self.stringValue = @((const char*)aSetting->value); break;
+ case ST_BOOL: self.booleanValue = *(bool*)aSetting->value; break;
+ case ST_BIND: [self updateInputString]; break;
+ default: break;
+ }
+}
+
+- (IBAction)doBrowse:(id)sender
+{
+ NSOpenPanel* panel = [NSOpenPanel new];
+ [panel runModal];
+
+ if (panel.URLs.count == 1)
+ self.stringValue = panel.URL.path;
+}
+
+- (void)setNumericValue:(NSNumber *)numericValue
+{
+ _numericValue = numericValue;
+
+ if (_setting && _setting->type == ST_INT)
+ *(int*)_setting->value = _numericValue.intValue;
+ else if (_setting && _setting->type == ST_FLOAT)
+ *(float*)_setting->value = _numericValue.floatValue;
+}
+
+- (void)setBooleanValue:(bool)booleanValue
+{
+ _booleanValue = booleanValue;
+
+ if (_setting && _setting->type == ST_BOOL)
+ *(bool*)_setting->value = _booleanValue;
+}
+
+- (void)setStringValue:(NSString *)stringValue
+{
+ _stringValue = stringValue ? stringValue : @"";
+
+ if (_setting && (_setting->type == ST_STRING || _setting->type == ST_PATH))
+ strlcpy(_setting->value, _stringValue.UTF8String, _setting->size);
+}
+
+// Input Binding
+- (void)updateInputString
+{
+ self.stringValue = [NSString stringWithFormat:@"[KB:%s] [JS:%s] [AX:%s]", key_name_for_rk(BINDFOR(*_setting).key),
+ get_button_name(_setting),
+ get_axis_name(_setting)];
+}
+
+- (void)dismissBinder
+{
+ [self.bindTimer invalidate];
+ self.bindTimer = nil;
+
+ [self updateInputString];
+
+ [(id)self.window.attachedSheet goAway:nil];
+}
+
+- (void)checkBind:(NSTimer*)send
+{
+ int32_t value = 0;
+
+ if ((value = apple_input_find_any_key()))
+ BINDFOR(*_setting).key = input_translate_keysym_to_rk(value);
+ else if ((value = apple_input_find_any_button(0)) >= 0)
+ BINDFOR(*_setting).joykey = value;
+ else if ((value = apple_input_find_any_axis(0)))
+ BINDFOR(*_setting).joyaxis = (value > 0) ? AXIS_POS(value - 1) : AXIS_NEG(value - 1);
+ else
+ return;
+
+ [self dismissBinder];
+}
+
+- (IBAction)doGetBind:(id)sender
+{
+ static NSWindowController* controller;
+ if (!controller)
+ controller = [[NSWindowController alloc] initWithWindowNibName:@"InputBinder"];
+
+ self.bindTimer = [NSTimer timerWithTimeInterval:.1f target:self selector:@selector(checkBind:) userInfo:nil repeats:YES];
+ [[NSRunLoop currentRunLoop] addTimer:self.bindTimer forMode:NSModalPanelRunLoopMode];
+
+ [NSApp beginSheet:controller.window modalForWindow:self.window modalDelegate:nil didEndSelector:nil contextInfo:nil];
+}
+
+@end
@interface RASettingsDelegate : NSObject
+ NSOutlineViewDataSource, NSOutlineViewDelegate,
+ NSWindowDelegate>
@end
@implementation RASettingsDelegate
{
- NSWindow IBOutlet* _window;
+ NSWindow IBOutlet* _inputWindow;
NSTableView IBOutlet* _table;
NSOutlineView IBOutlet* _outline;
@@ -33,10 +285,15 @@
- (void)awakeFromNib
{
+ apple_enter_stasis();
+
NSMutableArray* thisGroup = nil;
NSMutableArray* thisSubGroup = nil;
_settings = [NSMutableArray array];
-
+
+ memcpy(&fake_settings, &g_settings, sizeof(struct settings));
+ memcpy(&fake_extern, &g_extern, sizeof(struct global));
+
for (int i = 0; setting_data[i].type; i ++)
{
switch (setting_data[i].type)
@@ -44,7 +301,7 @@
case ST_GROUP:
{
thisGroup = [NSMutableArray array];
- objc_setAssociatedObject(thisGroup, "NAME", [NSString stringWithFormat:@"%s", setting_data[i].name], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+ objc_setAssociatedObject(thisGroup, associated_name_tag, [NSString stringWithFormat:@"%s", setting_data[i].name], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
break;
}
@@ -58,7 +315,7 @@
case ST_SUB_GROUP:
{
thisSubGroup = [NSMutableArray array];
- objc_setAssociatedObject(thisSubGroup, "NAME", [NSString stringWithFormat:@"%s", setting_data[i].name], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+ objc_setAssociatedObject(thisSubGroup, associated_name_tag, [NSString stringWithFormat:@"%s", setting_data[i].name], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
break;
}
@@ -77,49 +334,81 @@
}
}
- [NSApplication.sharedApplication beginSheet:_window modalForWindow:RetroArch_OSX.get->window modalDelegate:nil didEndSelector:nil contextInfo:nil];
- [NSApplication.sharedApplication runModalForWindow:_window];
+ [self load];
}
-- (IBAction)close:(id)sender
+- (void)load
{
- [NSApplication.sharedApplication stopModal];
- [NSApplication.sharedApplication endSheet:_window returnCode:0];
- [_window orderOut:nil];
+ config_file_t* conf = config_file_new(apple_platform.globalConfigFile.UTF8String);
+
+ for (int i = 0; setting_data[i].type; i ++)
+ {
+ switch (setting_data[i].type)
+ {
+ case ST_BOOL: config_get_bool (conf, setting_data[i].name, (bool*)setting_data[i].value); break;
+ case ST_INT: config_get_int (conf, setting_data[i].name, (int*)setting_data[i].value); break;
+ case ST_FLOAT: config_get_float (conf, setting_data[i].name, (float*)setting_data[i].value); break;
+ case ST_PATH: config_get_array (conf, setting_data[i].name, (char*)setting_data[i].value, setting_data[i].size); break;
+ case ST_STRING: config_get_array (conf, setting_data[i].name, (char*)setting_data[i].value, setting_data[i].size); break;
+
+ case ST_BIND:
+ {
+ input_config_parse_key (conf, "input_player1", setting_data[i].name, setting_data[i].value);
+ input_config_parse_joy_button(conf, "input_player1", setting_data[i].name, setting_data[i].value);
+ input_config_parse_joy_axis (conf, "input_player1", setting_data[i].name, setting_data[i].value);
+ break;
+ }
+
+ case ST_HEX: break;
+ default: break;
+ }
+ }
+ config_file_free(conf);
}
+- (void)windowWillClose:(NSNotification *)notification
+{
+ config_file_t* conf = config_file_new(apple_platform.globalConfigFile.UTF8String);
+ conf = conf ? conf : config_file_new(0);
+
+ for (int i = 0; setting_data[i].type; i ++)
+ {
+ switch (setting_data[i].type)
+ {
+ case ST_BOOL: config_set_bool (conf, setting_data[i].name, * (bool*)setting_data[i].value); break;
+ case ST_INT: config_set_int (conf, setting_data[i].name, * (int*)setting_data[i].value); break;
+ case ST_FLOAT: config_set_float (conf, setting_data[i].name, *(float*)setting_data[i].value); break;
+ case ST_PATH: config_set_string(conf, setting_data[i].name, (char*)setting_data[i].value); break;
+ case ST_STRING: config_set_string(conf, setting_data[i].name, (char*)setting_data[i].value); break;
+
+ case ST_BIND:
+ {
+ config_set_string(conf, get_input_config_key(&setting_data[i], 0 ), key_name_for_rk(BINDFOR(setting_data[i]).key));
+ config_set_string(conf, get_input_config_key(&setting_data[i], "btn" ), get_button_name(&setting_data[i]));
+ config_set_string(conf, get_input_config_key(&setting_data[i], "axis"), get_axis_name(&setting_data[i]));
+ break;
+ }
+
+ case ST_HEX: break;
+ default: break;
+ }
+ }
+ config_file_write(conf, apple_platform.globalConfigFile.UTF8String);
+ config_file_free(conf);
+
+ apple_exit_stasis(true);
+
+ [NSApp stopModal];
+}
#pragma mark View Builders
- (NSView*)labelAccessoryFor:(NSString*)text onTable:(NSTableView*)table
{
- NSTextField* result = [table makeViewWithIdentifier:@"label" owner:self];
- if (result == nil)
- {
- result = [NSTextField new];
- result.bordered = NO;
- result.drawsBackground = NO;
- result.identifier = @"label";
- }
-
+ RASettingCell* result = [table makeViewWithIdentifier:@"RALabelSetting" owner:nil];
result.stringValue = text;
return result;
}
-- (NSView*)booleanAccessoryFor:(const rarch_setting_t*)setting onTable:(NSTableView*)table
-{
- NSButton* result = [table makeViewWithIdentifier:@"boolean" owner:self];
-
- if (!result)
- {
- result = [NSButton new];
- result.buttonType = NSSwitchButton;
- result.title = @"";
- }
-
- result.state = *(bool*)setting->value;
- return result;
-}
-
#pragma mark Section Table
- (NSInteger)numberOfRowsInTableView:(NSTableView*)view
{
@@ -128,7 +417,7 @@
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
- return [self labelAccessoryFor:objc_getAssociatedObject(_settings[row], "NAME") onTable:tableView];
+ return [self labelAccessoryFor:objc_getAssociatedObject(_settings[row], associated_name_tag) onTable:tableView];
}
- (void)tableViewSelectionDidChange:(NSNotification *)aNotification
@@ -153,12 +442,16 @@
return [item isKindOfClass:[NSArray class]];
}
+- (BOOL)validateProposedFirstResponder:(NSResponder *)responder forEvent:(NSEvent *)event {
+ return YES;
+}
+
- (NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
if ([item isKindOfClass:[NSArray class]])
{
if ([tableColumn.identifier isEqualToString:@"title"])
- return [self labelAccessoryFor:objc_getAssociatedObject(item, "NAME") onTable:outlineView];
+ return [self labelAccessoryFor:objc_getAssociatedObject(item, associated_name_tag) onTable:outlineView];
else
return [self labelAccessoryFor:[NSString stringWithFormat:@"%d items", (int)[item count]] onTable:outlineView];
}
@@ -167,25 +460,22 @@
const rarch_setting_t* setting = &setting_data[[item intValue]];
if ([tableColumn.identifier isEqualToString:@"title"])
- return [self labelAccessoryFor:[NSString stringWithFormat:@"%s", setting->short_description] onTable:outlineView]; // < The outlineView will fill the value
+ return [self labelAccessoryFor:@(setting->short_description) onTable:outlineView];
else if([tableColumn.identifier isEqualToString:@"accessory"])
{
+ RASettingCell* s = nil;
switch (setting->type)
{
- case ST_BOOL: return [self booleanAccessoryFor:setting onTable:outlineView];
-
- case ST_PATH:
- case ST_STRING:
- return [self labelAccessoryFor:[NSString stringWithFormat:@"%s", (const char*)setting->value] onTable:outlineView];
-
- case ST_INT:
- return [self labelAccessoryFor:[NSString stringWithFormat:@"%d", *(int*)setting->value] onTable:outlineView];
-
- case ST_FLOAT:
- return [self labelAccessoryFor:[NSString stringWithFormat:@"%f", *(float*)setting->value] onTable:outlineView];
-
- default: abort();
+ case ST_BOOL: s = [outlineView makeViewWithIdentifier:@"RABooleanSetting" owner:nil]; break;
+ case ST_INT: s = [outlineView makeViewWithIdentifier:@"RANumericSetting" owner:nil]; break;
+ case ST_FLOAT: s = [outlineView makeViewWithIdentifier:@"RANumericSetting" owner:nil]; break;
+ case ST_PATH: s = [outlineView makeViewWithIdentifier:@"RAPathSetting" owner:nil]; break;
+ case ST_STRING: s = [outlineView makeViewWithIdentifier:@"RAStringSetting" owner:nil]; break;
+ case ST_BIND: s = [outlineView makeViewWithIdentifier:@"RABindSetting" owner:nil]; break;
+ default: break;
}
+ s.setting = setting;
+ return s;
}
}
diff --git a/apple/RetroArch/main.m b/apple/RetroArch/main.m
deleted file mode 100644
index 85247654d6..0000000000
--- a/apple/RetroArch/main.m
+++ /dev/null
@@ -1,711 +0,0 @@
-/* RetroArch - A frontend for libretro.
- * Copyright (C) 2013 - Jason Fetters
- *
- * RetroArch is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Found-
- * ation, either version 3 of the License, or (at your option) any later version.
- *
- * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with RetroArch.
- * If not, see .
- */
-
-#include
-#include
-
-#import "RetroArch_Apple.h"
-#include "rarch_wrapper.h"
-
-#include "apple_input.h"
-
-// If USE_XATTR is defined any loaded file will get a com.RetroArch.Core extended attribute
-// specifying which core was used to load.
-//#define USE_XATTR
-
-#ifdef IOS
-#import "views.h"
-#include "../iOS/input/BTStack/btpad.h"
-#include "../iOS/input/BTStack/btdynamic.h"
-#include "../iOS/input/BTStack/btpad.h"
-#elif defined(USE_XATTR)
-#include "sys/xattr.h"
-#endif
-
-#include "file.h"
-
-#define GSEVENT_TYPE_KEYDOWN 10
-#define GSEVENT_TYPE_KEYUP 11
-
-//#define HAVE_DEBUG_FILELOG
-static bool use_tv_mode;
-
-id apple_platform;
-
-// From frontend/frontend_ios.c
-extern void* rarch_main(void* args);
-extern void apple_frontend_post_event(void (*fn)(void*), void* userdata);
-
-
-// These are based on the tag property of the button used to trigger the event
-enum basic_event_t { RESET = 1, LOAD_STATE = 2, SAVE_STATE = 3, QUIT = 4 };
-static void event_basic_command(void* userdata)
-{
- switch ((enum basic_event_t)userdata)
- {
- case RESET: rarch_game_reset(); return;
- case LOAD_STATE: rarch_load_state(); return;
- case SAVE_STATE: rarch_save_state(); return;
- case QUIT: g_extern.system.shutdown = true; return;
- }
-}
-
-static void event_set_state_slot(void* userdata)
-{
- g_extern.state_slot = (uint32_t)userdata;
-}
-
-static void event_show_rgui(void* userdata)
-{
- const bool in_menu = g_extern.lifecycle_mode_state & (1 << MODE_MENU);
- g_extern.lifecycle_mode_state &= ~(1ULL << (in_menu ? MODE_MENU : MODE_GAME));
- g_extern.lifecycle_mode_state |= (1ULL << (in_menu ? MODE_GAME : MODE_MENU));
-}
-
-static void event_reload_config(void* userdata)
-{
- objc_clear_config_hack();
-
- uninit_drivers();
- config_load();
- init_drivers();
-}
-
-#pragma mark EMULATION
-static pthread_t apple_retro_thread;
-static bool apple_is_paused;
-static bool apple_is_running;
-static RAModuleInfo* apple_core;
-
-void apple_run_core(RAModuleInfo* core, const char* file)
-{
- if (!apple_is_running)
- {
- [apple_platform loadingCore:core withFile:file];
-
- apple_core = core;
- apple_is_running = true;
-
- struct rarch_main_wrap* load_data = malloc(sizeof(struct rarch_main_wrap));
- memset(load_data, 0, sizeof(struct rarch_main_wrap));
-
- load_data->config_path = strdup(apple_platform.retroarchConfigPath.UTF8String);
-
-#ifdef IOS
- load_data->sram_path = strdup(RetroArch_iOS.get.systemDirectory.UTF8String);
- load_data->state_path = strdup(RetroArch_iOS.get.systemDirectory.UTF8String);
-#endif
-
- if (file && core)
- {
- load_data->libretro_path = strdup(apple_core.path.UTF8String);
- load_data->rom_path = strdup(file);
- }
-
- if (pthread_create(&apple_retro_thread, 0, rarch_main, load_data))
- {
- apple_rarch_exited((void*)1);
- return;
- }
-
- pthread_detach(apple_retro_thread);
- }
-}
-
-void apple_rarch_exited(void* result)
-{
- if (result)
- apple_display_alert(@"Failed to load game.", 0);
-
- RAModuleInfo* used_core = apple_core;
- apple_core = nil;
-
- if (apple_is_running)
- {
- apple_is_running = false;
- [apple_platform unloadingCore:used_core];
- }
-
- if (use_tv_mode)
- apple_run_core(nil, 0);
-}
-
-//
-// IOS
-//
-#pragma mark IOS
-#ifdef IOS
-// Input helpers: This is kept here because it needs objective-c
-static void handle_touch_event(NSArray* touches)
-{
- const int numTouches = [touches count];
- const float scale = [[UIScreen mainScreen] scale];
-
- g_current_input_data.touch_count = 0;
-
- for(int i = 0; i != numTouches && g_current_input_data.touch_count < MAX_TOUCHES; i ++)
- {
- UITouch* touch = [touches objectAtIndex:i];
- const CGPoint coord = [touch locationInView:touch.view];
-
- if (touch.phase != UITouchPhaseEnded && touch.phase != UITouchPhaseCancelled)
- {
- g_current_input_data.touches[g_current_input_data.touch_count ].screen_x = coord.x * scale;
- g_current_input_data.touches[g_current_input_data.touch_count ++].screen_y = coord.y * scale;
- }
- }
-}
-
-@interface RApplication : UIApplication
-@end
-
-@implementation RApplication
-
-- (void)sendEvent:(UIEvent *)event
-{
- [super sendEvent:event];
-
- if ([[event allTouches] count])
- handle_touch_event(event.allTouches.allObjects);
- else if ([event respondsToSelector:@selector(_gsEvent)])
- {
- // Stolen from: http://nacho4d-nacho4d.blogspot.com/2012/01/catching-keyboard-events-in-ios.html
- uint8_t* eventMem = (uint8_t*)(void*)CFBridgingRetain([event performSelector:@selector(_gsEvent)]);
- int eventType = eventMem ? *(int*)&eventMem[8] : 0;
-
- if (eventType == GSEVENT_TYPE_KEYDOWN || eventType == GSEVENT_TYPE_KEYUP)
- apple_input_handle_key_event(*(uint16_t*)&eventMem[0x3C], eventType == GSEVENT_TYPE_KEYDOWN);
-
- CFBridgingRelease(eventMem);
- }
-}
-
-int main(int argc, char *argv[])
-{
- @autoreleasepool {
-#if defined(HAVE_DEBUG_FILELOG) && (TARGET_IPHONE_SIMULATOR == 0)
- NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
- NSString *documentsDirectory = [paths objectAtIndex:0];
- NSString *logPath = [documentsDirectory stringByAppendingPathComponent:@"console_stdout.log"];
- freopen([logPath cStringUsingEncoding:NSASCIIStringEncoding], "a", stdout);
- freopen([logPath cStringUsingEncoding:NSASCIIStringEncoding], "a", stderr);
-#endif
- return UIApplicationMain(argc, argv, NSStringFromClass([RApplication class]), NSStringFromClass([RetroArch_iOS class]));
- }
-}
-
-@end
-
-@implementation RetroArch_iOS
-{
- UIWindow* _window;
-
- bool _isGameTop, _isRomList;
- uint32_t _settingMenusInBackStack;
- uint32_t _enabledOrientations;
-
- RAModuleInfo* _module;
-}
-
-+ (RetroArch_iOS*)get
-{
- return (RetroArch_iOS*)[[UIApplication sharedApplication] delegate];
-}
-
-// UIApplicationDelegate
-- (void)applicationDidFinishLaunching:(UIApplication *)application
-{
- apple_platform = self;
- self.delegate = self;
-
- // Setup window
- _window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
- _window.rootViewController = self;
- [_window makeKeyAndVisible];
-
- // Build system paths and test permissions
- self.documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
- self.systemDirectory = [self.documentsDirectory stringByAppendingPathComponent:@".RetroArch"];
- self.systemConfigPath = [self.systemDirectory stringByAppendingPathComponent:@"frontend.cfg"];
-
- if (!path_make_and_check_directory(self.documentsDirectory.UTF8String, 0755, R_OK | W_OK | X_OK))
- apple_display_alert([NSString stringWithFormat:@"Failed to create or access base directory: %@", self.documentsDirectory], 0);
- else if (!path_make_and_check_directory(self.systemDirectory.UTF8String, 0755, R_OK | W_OK | X_OK))
- apple_display_alert([NSString stringWithFormat:@"Failed to create or access system directory: %@", self.systemDirectory], 0);
- else
- {
- [self pushViewController:[RADirectoryList directoryListAtBrowseRoot] animated:YES];
- [self refreshSystemConfig];
-
- if (use_tv_mode)
- apple_run_core(nil, 0);
- }
-
- // Warn if there are no cores present
- if ([RAModuleInfo getModules].count == 0)
- apple_display_alert(@"No libretro cores were found. You will not be able to play any games.", 0);
-}
-
-- (void)applicationWillEnterForeground:(UIApplication *)application
-{
- [RAGameView.get resume];
-}
-
-- (void)applicationDidEnterBackground:(UIApplication *)application
-{
- [RAGameView.get suspend];
-}
-
-// UINavigationControllerDelegate
-- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
-{
- _isGameTop = [viewController isKindOfClass:[RAGameView class]];
- _isRomList = [viewController isKindOfClass:[RADirectoryList class]];
-
- [[UIApplication sharedApplication] setStatusBarHidden:_isGameTop withAnimation:UIStatusBarAnimationNone];
- [[UIApplication sharedApplication] setIdleTimerDisabled:_isGameTop];
-
- self.navigationBarHidden = _isGameTop;
- [self setToolbarHidden:!_isRomList animated:YES];
- self.topViewController.navigationItem.rightBarButtonItem = [self createSettingsButton];
-}
-
-// UINavigationController: Never animate when pushing onto, or popping, an RAGameView
-- (void)pushViewController:(UIViewController*)theView animated:(BOOL)animated
-{
- if ([theView respondsToSelector:@selector(isSettingsView)] && [(id)theView isSettingsView])
- _settingMenusInBackStack ++;
-
- [super pushViewController:theView animated:animated && !_isGameTop];
-}
-
-- (UIViewController*)popViewControllerAnimated:(BOOL)animated
-{
- if ([self.topViewController respondsToSelector:@selector(isSettingsView)] && [(id)self.topViewController isSettingsView])
- _settingMenusInBackStack --;
-
- return [super popViewControllerAnimated:animated && !_isGameTop];
-}
-
-// NOTE: This version only runs on iOS6
-- (NSUInteger)supportedInterfaceOrientations
-{
- return _isGameTop ? _enabledOrientations
- : UIInterfaceOrientationMaskAll;
-}
-
-// NOTE: This version runs on iOS2-iOS5, but not iOS6
-- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
-{
- if (_isGameTop)
- switch (interfaceOrientation)
- {
- case UIInterfaceOrientationPortrait:
- return (_enabledOrientations & UIInterfaceOrientationMaskPortrait);
- case UIInterfaceOrientationPortraitUpsideDown:
- return (_enabledOrientations & UIInterfaceOrientationMaskPortraitUpsideDown);
- case UIInterfaceOrientationLandscapeLeft:
- return (_enabledOrientations & UIInterfaceOrientationMaskLandscapeLeft);
- case UIInterfaceOrientationLandscapeRight:
- return (_enabledOrientations & UIInterfaceOrientationMaskLandscapeRight);
- }
-
- return YES;
-}
-
-
-#pragma mark RetroArch_Platform
-- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file
-{
- [self pushViewController:RAGameView.get animated:NO];
- [RASettingsList refreshModuleConfig:core];
-
- btpad_set_inquiry_state(false);
-
- [self refreshSystemConfig];
-}
-
-- (void)unloadingCore:(RAModuleInfo*)core
-{
- [self popToViewController:[RAGameView get] animated:NO];
- [self popViewControllerAnimated:NO];
-
- btpad_set_inquiry_state(true);
-}
-
-- (NSString*)retroarchConfigPath
-{
- return [NSString stringWithFormat:@"%@/retroarch.cfg", self.systemDirectory];
-}
-
-- (NSString*)corePath
-{
- return [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"modules"];
-}
-
-- (void)refreshConfig
-{
- if (apple_is_running)
- apple_frontend_post_event(&event_reload_config, 0);
- else
- objc_clear_config_hack();
-}
-
-- (void)refreshSystemConfig
-{
- // Read load time settings
- config_file_t* conf = config_file_new([self.systemConfigPath UTF8String]);
-
- if (conf)
- {
- // Get enabled orientations
- static const struct { const char* setting; uint32_t orientation; } orientationSettings[4] =
- {
- { "ios_allow_portrait", UIInterfaceOrientationMaskPortrait },
- { "ios_allow_portrait_upside_down", UIInterfaceOrientationMaskPortraitUpsideDown },
- { "ios_allow_landscape_left", UIInterfaceOrientationMaskLandscapeLeft },
- { "ios_allow_landscape_right", UIInterfaceOrientationMaskLandscapeRight }
- };
-
- _enabledOrientations = 0;
-
- for (int i = 0; i < 4; i ++)
- {
- bool enabled = false;
- bool found = config_get_bool(conf, orientationSettings[i].setting, &enabled);
-
- if (!found || enabled)
- _enabledOrientations |= orientationSettings[i].orientation;
- }
-
- //
- bool val;
- apple_input_enable_icade(config_get_bool(conf, "ios_use_icade", &val) && val);
- btstack_set_poweron(config_get_bool(conf, "ios_use_btstack", &val) && val);
- use_tv_mode = config_get_bool(conf, "ios_tv_mode", & val) && val;
-
- config_file_free(conf);
- }
-}
-
-#pragma mark PAUSE MENU
-- (UIBarButtonItem*)createSettingsButton
-{
- if (_settingMenusInBackStack == 0)
- return [[UIBarButtonItem alloc]
- initWithTitle:@"Settings"
- style:UIBarButtonItemStyleBordered
- target:[RetroArch_iOS get]
- action:@selector(showSystemSettings)];
-
- else
- return nil;
-}
-
-- (IBAction)showPauseMenu:(id)sender
-{
- if (apple_is_running && !apple_is_paused && _isGameTop)
- {
- apple_is_paused = true;
- [[RAGameView get] openPauseMenu];
-
- btpad_set_inquiry_state(true);
- }
-}
-
-- (IBAction)basicEvent:(id)sender
-{
- if (apple_is_running)
- apple_frontend_post_event(&event_basic_command, ((UIView*)sender).tag);
-
- [self closePauseMenu:sender];
-}
-
-- (IBAction)chooseState:(id)sender
-{
- if (apple_is_running)
- apple_frontend_post_event(event_set_state_slot, (void*)((UISegmentedControl*)sender).selectedSegmentIndex);
-}
-
-- (IBAction)showRGUI:(id)sender
-{
- if (apple_is_running)
- apple_frontend_post_event(event_show_rgui, 0);
-
- [self closePauseMenu:sender];
-}
-
-- (IBAction)closePauseMenu:(id)sender
-{
- [[RAGameView get] closePauseMenu];
- apple_is_paused = false;
-
- btpad_set_inquiry_state(false);
-}
-
-- (IBAction)showSettings
-{
- [self pushViewController:[[RASettingsList alloc] initWithModule:_module] animated:YES];
-}
-
-- (IBAction)showSystemSettings
-{
- [self pushViewController:[RASystemSettingsList new] animated:YES];
-}
-
-@end
-
-
-#endif
-
-//
-// OSX
-//
-#pragma mark OSX
-#ifdef OSX
-
-@interface RApplication : NSApplication
-@end
-
-@implementation RApplication
-
-- (void)sendEvent:(NSEvent *)event
-{
- [super sendEvent:event];
-
- if (event.type == GSEVENT_TYPE_KEYDOWN || event.type == GSEVENT_TYPE_KEYUP)
- apple_input_handle_key_event(event.keyCode, event.type == GSEVENT_TYPE_KEYDOWN);
-}
-
-@end
-
-@implementation RetroArch_OSX
-{
- NSWindow IBOutlet* _coreSelectSheet;
-
- bool _isTerminating;
- bool _loaded;
- bool _wantReload;
- NSString* _file;
- RAModuleInfo* _core;
-}
-
-+ (RetroArch_OSX*)get
-{
- return (RetroArch_OSX*)[[NSApplication sharedApplication] delegate];
-}
-
-- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
-{
- apple_platform = self;
- _loaded = true;
-
- [window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
-
- RAGameView.get.frame = [window.contentView bounds];
- [window.contentView setAutoresizesSubviews:YES];
- [window.contentView addSubview:RAGameView.get];
- [window makeFirstResponder:RAGameView.get];
-
- // Create core select list
- NSComboBox* cb = (NSComboBox*)[_coreSelectSheet.contentView viewWithTag:1];
-
- for (RAModuleInfo* i in RAModuleInfo.getModules)
- [cb addItemWithObjectValue:i];
-
- if (cb.numberOfItems)
- [cb selectItemAtIndex:0];
- else
- apple_display_alert(@"No libretro cores were found.", @"RetroArch");
-
- // Run RGUI if needed
- if (!_wantReload)
- apple_run_core(nil, 0);
- else
- [self chooseCore];
-
- _wantReload = false;
-
- extern void osx_pad_init();
- osx_pad_init();
-}
-
-- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
-{
- return YES;
-}
-
-- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
-{
- _isTerminating = true;
-
- if (apple_is_running)
- apple_frontend_post_event(event_basic_command, (void*)QUIT);
-
- return apple_is_running ? NSTerminateCancel : NSTerminateNow;
-}
-
-
-- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames
-{
- if (filenames.count == 1 && filenames[0])
- {
- _file = filenames[0];
-
- if (!_loaded)
- _wantReload = true;
- else
- [self chooseCore];
-
- [sender replyToOpenOrPrint:NSApplicationDelegateReplySuccess];
- }
- else
- {
- apple_display_alert(@"Cannot open multiple files", @"RetroArch");
- [sender replyToOpenOrPrint:NSApplicationDelegateReplyFailure];
- }
-}
-
-- (void)openDocument:(id)sender
-{
- NSOpenPanel* panel = [NSOpenPanel openPanel];
- [panel beginSheetModalForWindow:window completionHandler:^(NSInteger result)
- {
- [NSApplication.sharedApplication stopModal];
-
- if (result == NSOKButton && panel.URL)
- {
- _file = panel.URL.path;
- [self performSelector:@selector(chooseCore) withObject:nil afterDelay:.5f];
- }
- }];
- [NSApplication.sharedApplication runModalForWindow:panel];
-}
-
-// This utility function will queue the _core and _file instance values for running.
-// If the emulator thread is already running it will tell it to quit.
-- (void)runCore
-{
- _wantReload = apple_is_running;
-
- if (!apple_is_running)
- apple_run_core(_core, _file.UTF8String);
- else
- apple_frontend_post_event(event_basic_command, (void*)QUIT);
-}
-
-- (void)chooseCore
-{
-#ifdef USE_XATTR
- char stored_name[PATH_MAX];
- if (getxattr(_file.UTF8String, "com.RetroArch.Core", stored_name, PATH_MAX, 0, 0) > 0)
- {
- for (RAModuleInfo* i in RAModuleInfo.getModules)
- {
- const char* core_name = i.path.lastPathComponent.UTF8String;
- if (strcmp(core_name, stored_name) == 0)
- {
- _core = i;
- [self runCore];
- return;
- }
- }
- }
-#endif
-
- [NSApplication.sharedApplication beginSheet:_coreSelectSheet modalForWindow:window modalDelegate:nil didEndSelector:nil contextInfo:nil];
- [NSApplication.sharedApplication runModalForWindow:_coreSelectSheet];
-}
-
-- (IBAction)coreWasChosen:(id)sender
-{
- [NSApplication.sharedApplication stopModal];
- [NSApplication.sharedApplication endSheet:_coreSelectSheet returnCode:0];
- [_coreSelectSheet orderOut:self];
-
- if (_isTerminating)
- return;
-
- NSComboBox* cb = (NSComboBox*)[_coreSelectSheet.contentView viewWithTag:1];
- _core = (RAModuleInfo*)cb.objectValueOfSelectedItem;
-
- [self runCore];
-}
-
-#pragma mark RetroArch_Platform
-- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file
-{
- if (file)
- {
- [NSDocumentController.sharedDocumentController noteNewRecentDocumentURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:file]]];
-
-#ifdef USE_XATTR
- const char* core_name = core.path.lastPathComponent.UTF8String;
- setxattr(file, "com.RetroArch.Core", core_name, strlen(core_name) + 1, 0, 0);
-#endif
- }
-}
-
-- (void)unloadingCore:(RAModuleInfo*)core
-{
- if (_isTerminating)
- [NSApplication.sharedApplication terminate:nil];
-
- if (_wantReload)
- apple_run_core(_core, _file.UTF8String);
- else if(use_tv_mode)
- apple_run_core(nil, 0);
- else
- [NSApplication.sharedApplication terminate:nil];
-
- _wantReload = false;
-}
-
-- (NSString*)retroarchConfigPath
-{
- NSArray* paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
- return [paths[0] stringByAppendingPathComponent:@"RetroArch/retroarch.cfg"];
-}
-
-- (NSString*)corePath
-{
- return [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"Contents/Resources/modules"];
-}
-
-#pragma mark Menus
-- (IBAction)showPreferences:(id)sender
-{
- [[[NSWindowController alloc] initWithWindowNibName:@"Settings"] window];
-}
-
-- (IBAction)basicEvent:(id)sender
-{
- if (apple_is_running)
- apple_frontend_post_event(&event_basic_command, (void*)((NSMenuItem*)sender).tag);
-}
-
-- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
-{
- [NSApplication.sharedApplication stopModal];
-}
-
-@end
-
-int main(int argc, char *argv[])
-{
- return NSApplicationMain(argc, (const char **) argv);
-}
-
-#endif
diff --git a/apple/RetroArch_OSX.xcodeproj/project.pbxproj b/apple/RetroArch_OSX.xcodeproj/project.pbxproj
index e4b16ceb4a..11fc233503 100644
--- a/apple/RetroArch_OSX.xcodeproj/project.pbxproj
+++ b/apple/RetroArch_OSX.xcodeproj/project.pbxproj
@@ -8,9 +8,11 @@
/* Begin PBXBuildFile section */
9620F663178FD4D3001B3B81 /* settings.m in Sources */ = {isa = PBXBuildFile; fileRef = 9620F662178FD4D3001B3B81 /* settings.m */; };
- 9620F6651790004F001B3B81 /* Settings.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9620F6641790004F001B3B81 /* Settings.xib */; };
962EE0E2178B3DF6004224FF /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 962EE0E1178B3DF6004224FF /* IOKit.framework */; };
96355CE31788E72A0010DBFA /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96355CE21788E72A0010DBFA /* Cocoa.framework */; };
+ 9646869817BBC14E00C5EA69 /* platform.m in Sources */ = {isa = PBXBuildFile; fileRef = 9646869617BBC14E00C5EA69 /* platform.m */; };
+ 964DE7C117D84B34001CBB6C /* InputBinder.xib in Resources */ = {isa = PBXBuildFile; fileRef = 964DE7C317D84B34001CBB6C /* InputBinder.xib */; };
+ 964DE7C417D84B57001CBB6C /* Settings.xib in Resources */ = {isa = PBXBuildFile; fileRef = 964DE7C617D84B57001CBB6C /* Settings.xib */; };
967894931788ECDB00D6CA69 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 9678948F1788ECDB00D6CA69 /* InfoPlist.strings */; };
967894941788ECDB00D6CA69 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 967894911788ECDB00D6CA69 /* MainMenu.xib */; };
967894961788ED1100D6CA69 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 967894951788ED1100D6CA69 /* main.m */; };
@@ -28,13 +30,16 @@
/* Begin PBXFileReference section */
9620F662178FD4D3001B3B81 /* settings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = settings.m; path = OSX/settings.m; sourceTree = SOURCE_ROOT; };
- 9620F6641790004F001B3B81 /* Settings.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = Settings.xib; path = OSX/Settings.xib; sourceTree = ""; };
962EE0E1178B3DF6004224FF /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = ../../../../../../../System/Library/Frameworks/IOKit.framework; sourceTree = ""; };
96355CDF1788E72A0010DBFA /* RetroArch.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RetroArch.app; sourceTree = BUILT_PRODUCTS_DIR; };
96355CE21788E72A0010DBFA /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
96355CE51788E72A0010DBFA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
96355CE61788E72A0010DBFA /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
96355CE71788E72A0010DBFA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+ 9646869617BBC14E00C5EA69 /* platform.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = platform.m; path = OSX/platform.m; sourceTree = SOURCE_ROOT; };
+ 9646869717BBC14E00C5EA69 /* platform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = platform.h; path = OSX/platform.h; sourceTree = SOURCE_ROOT; };
+ 964DE7C217D84B34001CBB6C /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/InputBinder.xib; sourceTree = ""; };
+ 964DE7C517D84B57001CBB6C /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/Settings.xib; sourceTree = ""; };
9678948D1788ECCA00D6CA69 /* RetroArch-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "RetroArch-Info.plist"; path = "OSX/RetroArch-Info.plist"; sourceTree = SOURCE_ROOT; };
967894901788ECDB00D6CA69 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = OSX/en.lproj/InfoPlist.strings; sourceTree = SOURCE_ROOT; };
967894921788ECDB00D6CA69 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = OSX/en.lproj/MainMenu.xib; sourceTree = SOURCE_ROOT; };
@@ -75,7 +80,7 @@
isa = PBXGroup;
children = (
962EE0E1178B3DF6004224FF /* IOKit.framework */,
- 96355CE81788E72A0010DBFA /* RetroArch */,
+ 96355CE81788E72A0010DBFA /* common */,
967894E7178A2E9B00D6CA69 /* Assets */,
96355CE11788E72A0010DBFA /* Frameworks */,
96355CE01788E72A0010DBFA /* Products */,
@@ -106,9 +111,11 @@
name = Frameworks;
sourceTree = "";
};
- 96355CE81788E72A0010DBFA /* RetroArch */ = {
+ 96355CE81788E72A0010DBFA /* common */ = {
isa = PBXGroup;
children = (
+ 9646869617BBC14E00C5EA69 /* platform.m */,
+ 9646869717BBC14E00C5EA69 /* platform.h */,
9620F662178FD4D3001B3B81 /* settings.m */,
967894A01788F07D00D6CA69 /* griffin.c */,
967894971788F02600D6CA69 /* RAGameView.m */,
@@ -119,7 +126,7 @@
9678949C1788F02600D6CA69 /* utility.m */,
967894951788ED1100D6CA69 /* main.m */,
);
- path = RetroArch;
+ path = common;
sourceTree = "";
};
96355CE91788E72A0010DBFA /* Supporting Files */ = {
@@ -138,7 +145,8 @@
967894E8178A2EB400D6CA69 /* modules */,
967894911788ECDB00D6CA69 /* MainMenu.xib */,
C15874EE178F2094001171D4 /* RetroArch.icns */,
- 9620F6641790004F001B3B81 /* Settings.xib */,
+ 964DE7C617D84B57001CBB6C /* Settings.xib */,
+ 964DE7C317D84B34001CBB6C /* InputBinder.xib */,
);
name = Assets;
sourceTree = "";
@@ -197,7 +205,8 @@
967894941788ECDB00D6CA69 /* MainMenu.xib in Resources */,
967894E9178A2EB400D6CA69 /* modules in Resources */,
C15874EF178F2094001171D4 /* RetroArch.icns in Resources */,
- 9620F6651790004F001B3B81 /* Settings.xib in Resources */,
+ 964DE7C417D84B57001CBB6C /* Settings.xib in Resources */,
+ 964DE7C117D84B34001CBB6C /* InputBinder.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -214,12 +223,31 @@
9678949F1788F02600D6CA69 /* utility.m in Sources */,
967894A11788F07D00D6CA69 /* griffin.c in Sources */,
9620F663178FD4D3001B3B81 /* settings.m in Sources */,
+ 9646869817BBC14E00C5EA69 /* platform.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
+ 964DE7C317D84B34001CBB6C /* InputBinder.xib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 964DE7C217D84B34001CBB6C /* en */,
+ );
+ name = InputBinder.xib;
+ path = OSX;
+ sourceTree = "";
+ };
+ 964DE7C617D84B57001CBB6C /* Settings.xib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 964DE7C517D84B57001CBB6C /* en */,
+ );
+ name = Settings.xib;
+ path = OSX;
+ sourceTree = "";
+ };
9678948F1788ECDB00D6CA69 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
@@ -262,7 +290,6 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
@@ -278,7 +305,6 @@
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
@@ -297,7 +323,6 @@
"-DINLINE=inline",
"-DLSB_FIRST",
"-D__LIBRETRO__",
- "-DRARCH_PERFORMANCE_MODE",
"-DWANT_RPNG",
"-DHAVE_COREAUDIO",
"-DHAVE_DYNAMIC",
@@ -321,7 +346,6 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
@@ -331,7 +355,6 @@
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
@@ -343,23 +366,22 @@
"-DHAVE_RARCH_MAIN_WRAP",
"-DHAVE_GRIFFIN",
"-DHAVE_RGUI",
- "-DIOS",
+ "-DOSX",
"-DHAVE_OPENGL",
"-DHAVE_FBO",
"-DHAVE_VID_CONTEXT",
- "-DHAVE_OPENGLES2",
"-DHAVE_GLSL",
"-DINLINE=inline",
"-DLSB_FIRST",
"-D__LIBRETRO__",
- "-DRARCH_PERFORMANCE_MODE",
- "-DRARCH_MOBILE",
+ "-DWANT_RPNG",
"-DHAVE_COREAUDIO",
"-DHAVE_DYNAMIC",
"-DHAVE_OVERLAY",
"-DHAVE_ZLIB",
"-DWANT_MINIZ",
"-DSINC_LOWER_QUALITY",
+ "-DHAVE_NETPLAY",
);
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = "";
diff --git a/apple/RetroArch_iOS.xcodeproj/project.pbxproj b/apple/RetroArch_iOS.xcodeproj/project.pbxproj
index 15081fd2eb..a603b05390 100644
--- a/apple/RetroArch_iOS.xcodeproj/project.pbxproj
+++ b/apple/RetroArch_iOS.xcodeproj/project.pbxproj
@@ -16,6 +16,7 @@
96366C5516C9AC3300D64A22 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96366C5416C9AC3300D64A22 /* CoreAudio.framework */; };
96366C5916C9ACF500D64A22 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96366C5816C9ACF500D64A22 /* AudioToolbox.framework */; };
963F5AC816CC523B009BBD19 /* RAGameView.m in Sources */ = {isa = PBXBuildFile; fileRef = 963F5AC516CC523B009BBD19 /* RAGameView.m */; };
+ 9646869517BBBEAE00C5EA69 /* platform.m in Sources */ = {isa = PBXBuildFile; fileRef = 9646869417BBBEAE00C5EA69 /* platform.m */; };
966B9CBD16E41E7A005B61E1 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 966B9CB816E41E7A005B61E1 /* Default-568h@2x.png */; };
966B9CBF16E41E7A005B61E1 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = 966B9CB916E41E7A005B61E1 /* Default.png */; };
966B9CC116E41E7A005B61E1 /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 966B9CBA16E41E7A005B61E1 /* Default@2x.png */; };
@@ -49,6 +50,7 @@
96366C5416C9AC3300D64A22 /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; };
96366C5816C9ACF500D64A22 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
963F5AC516CC523B009BBD19 /* RAGameView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RAGameView.m; sourceTree = ""; };
+ 9646869417BBBEAE00C5EA69 /* platform.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = platform.m; path = iOS/platform.m; sourceTree = SOURCE_ROOT; };
966B9CB816E41E7A005B61E1 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; };
966B9CB916E41E7A005B61E1 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; };
966B9CBA16E41E7A005B61E1 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; };
@@ -118,7 +120,7 @@
96AFAE1A16C1D4EA009DE44C = {
isa = PBXGroup;
children = (
- 96AFAE3316C1D4EA009DE44C /* RetroArch */,
+ 96AFAE3316C1D4EA009DE44C /* common */,
96AFAE9C16C1D976009DE44C /* core */,
966B9CB716E41E7A005B61E1 /* Assets */,
96AFAE2816C1D4EA009DE44C /* Frameworks */,
@@ -149,9 +151,10 @@
name = Frameworks;
sourceTree = "";
};
- 96AFAE3316C1D4EA009DE44C /* RetroArch */ = {
+ 96AFAE3316C1D4EA009DE44C /* common */ = {
isa = PBXGroup;
children = (
+ 9646869417BBBEAE00C5EA69 /* platform.m */,
967894571788EAAE00D6CA69 /* browser.m */,
967894581788EAAE00D6CA69 /* RALogView.m */,
967894591788EAAE00D6CA69 /* settings.m */,
@@ -164,7 +167,7 @@
96355CD11788CF190010DBFA /* RetroArch_Apple.h */,
96337E81176AC6E5004685F3 /* utility.m */,
);
- path = RetroArch;
+ path = common;
sourceTree = "";
};
96AFAE3416C1D4EA009DE44C /* Supporting Files */ = {
@@ -305,6 +308,7 @@
9678945B1788EAAE00D6CA69 /* browser.m in Sources */,
9678945C1788EAAE00D6CA69 /* RALogView.m in Sources */,
9678945D1788EAAE00D6CA69 /* settings.m in Sources */,
+ 9646869517BBBEAE00C5EA69 /* platform.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -363,7 +367,6 @@
"-DLSB_FIRST",
"-DHAVE_THREAD",
"-D__LIBRETRO__",
- "-DRARCH_PERFORMANCE_MODE",
"-DRARCH_MOBILE",
"-std=gnu99",
"-DHAVE_COREAUDIO",
@@ -413,7 +416,6 @@
"-DLSB_FIRST",
"-DHAVE_THREAD",
"-D__LIBRETRO__",
- "-DRARCH_PERFORMANCE_MODE",
"-DRARCH_MOBILE",
"-std=gnu99",
"-DHAVE_COREAUDIO",
@@ -454,7 +456,6 @@
"-DINLINE=inline",
"-DLSB_FIRST",
"-D__LIBRETRO__",
- "-DRARCH_PERFORMANCE_MODE",
"-DRARCH_MOBILE",
"-DHAVE_COREAUDIO",
"-DHAVE_DYNAMIC",
@@ -497,7 +498,6 @@
"-DINLINE=inline",
"-DLSB_FIRST",
"-D__LIBRETRO__",
- "-DRARCH_PERFORMANCE_MODE",
"-DRARCH_MOBILE",
"-DHAVE_COREAUDIO",
"-DHAVE_DYNAMIC",
diff --git a/apple/RetroArch/RAGameView.m b/apple/common/RAGameView.m
similarity index 50%
rename from apple/RetroArch/RAGameView.m
rename to apple/common/RAGameView.m
index a9b8f174a4..0527bf565c 100644
--- a/apple/RetroArch/RAGameView.m
+++ b/apple/common/RAGameView.m
@@ -17,15 +17,48 @@
#include "rarch_wrapper.h"
#include "general.h"
+#include "gfx/gfx_common.h"
+#include "gfx/gfx_context.h"
+
+// Define compatibility symbols and categories
+#ifdef IOS
+#define APP_HAS_FOCUS ([UIApplication sharedApplication].applicationState == UIApplicationStateActive)
+
+#define GLContextClass EAGLContext
+#define GLAPIType GFX_CTX_OPENGL_ES_API
+#define GLFrameworkID CFSTR("com.apple.opengles")
+#define RAScreen UIScreen
+
+@interface EAGLContext (OSXCompat) @end
+@implementation EAGLContext (OSXCompat)
++ (void)clearCurrentContext { EAGLContext.currentContext = nil; }
+- (void)makeCurrentContext { EAGLContext.currentContext = self; }
+@end
+
+#elif defined(OSX)
+#define APP_HAS_FOCUS ([NSApp isActive])
+
+#define GLContextClass NSOpenGLContext
+#define GLAPIType GFX_CTX_OPENGL_API
+#define GLFrameworkID CFSTR("com.apple.opengl")
+#define RAScreen NSScreen
+
+#define g_view g_instance // < RAGameView is a container on iOS; on OSX these are both the same object
+
+@interface NSScreen (IOSCompat) @end
+@implementation NSScreen (IOSCompat)
+- (CGRect)bounds { return CGRectMake(0, 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame)); }
+- (float) scale { return 1.0f; }
+@end
+
+#endif
+
#ifdef IOS
#import "views.h"
-
static const float ALMOST_INVISIBLE = .021f;
-static RAGameView* g_instance;
static GLKView* g_view;
-static EAGLContext* g_context;
static UIView* g_pause_view;
static UIView* g_pause_indicator_view;
@@ -33,16 +66,19 @@ static UIView* g_pause_indicator_view;
#include "apple_input.h"
-static RAGameView* g_instance;
-static NSOpenGLContext* g_context;
-
-#define g_view g_instance // < RAGameView is a container on iOS; on OSX these are both the same object
+static bool g_has_went_fullscreen;
+static NSOpenGLPixelFormat* g_format;
#endif
+
+static bool g_initialized;
+static RAGameView* g_instance;
+static GLContextClass* g_context;
+
static int g_fast_forward_skips;
static bool g_is_syncing = true;
-static float g_screen_scale = 1.0f;
+
@implementation RAGameView
+ (RAGameView*)get
@@ -57,30 +93,22 @@ static float g_screen_scale = 1.0f;
- (id)init
{
- static const NSOpenGLPixelFormatAttribute attributes [] = {
- NSOpenGLPFAWindow,
- NSOpenGLPFADoubleBuffer, // double buffered
- NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)16, // 16 bit depth buffer
- (NSOpenGLPixelFormatAttribute)nil
- };
-
- self = [super initWithFrame:CGRectMake(0, 0, 100, 100) pixelFormat:[[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]];
- self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
-
- g_context = self.openGLContext;
- [g_context makeCurrentContext];
-
+ self = [super init];
+ self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
return self;
}
+- (void)setFrame:(NSRect)frameRect
+{
+ [super setFrame:frameRect];
+
+ if (g_view && g_context)
+ [g_context update];
+}
+
- (void)display
{
- [self.openGLContext flushBuffer];
-}
-
-- (void)bindDrawable
-{
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ [g_context flushBuffer];
}
// Stop the annoying sound when pressing a key
@@ -121,8 +149,6 @@ static float g_screen_scale = 1.0f;
{
self = [super init];
- g_screen_scale = [[UIScreen mainScreen] scale];
-
UINib* xib = [UINib nibWithNibName:@"PauseView" bundle:nil];
g_pause_view = [[xib instantiateWithOwner:[RetroArch_iOS get] options:nil] lastObject];
@@ -189,115 +215,189 @@ static float g_screen_scale = 1.0f;
];
}
-- (void)suspend
-{
- g_view.context = nil;
- [EAGLContext setCurrentContext:nil];
-}
-
-- (void)resume
-{
- g_view.context = g_context;
- [EAGLContext setCurrentContext:g_context];
-}
#endif
@end
-// Realistically these functions don't create or destroy the view; just the OpenGL context.
-bool apple_init_game_view()
+static RAScreen* get_chosen_screen()
{
-#ifdef IOS
- dispatch_sync(dispatch_get_main_queue(), ^{
+ unsigned monitor = g_settings.video.monitor_index;
+
+ if (monitor >= RAScreen.screens.count)
+ {
+ RARCH_WARN("video_monitor_index is greater than the number of connected monitors; using main screen instead.\n");
+ return RAScreen.mainScreen;
+ }
+
+ return RAScreen.screens[monitor];
+}
+
+bool apple_gfx_ctx_init()
+{
+ dispatch_sync(dispatch_get_main_queue(),
+ ^{
// Make sure the view was created
- [RAGameView get];
-
- g_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
- [EAGLContext setCurrentContext:g_context];
- g_view.context = g_context;
-
- // Show pause button for a few seconds, so people know it's there
+ [RAGameView get];
+
+#ifdef IOS // Show pause button for a few seconds, so people know it's there
g_pause_indicator_view.alpha = 1.0f;
[NSObject cancelPreviousPerformRequestsWithTarget:g_instance];
[g_instance performSelector:@selector(hidePauseButton) withObject:g_instance afterDelay:3.0f];
+#endif
});
- [EAGLContext setCurrentContext:g_context];
-#else
- [g_context makeCurrentContext];
-#endif
+ g_initialized = true;
+
return true;
}
-void apple_destroy_game_view()
+void apple_gfx_ctx_destroy()
{
- dispatch_sync(dispatch_get_main_queue(), ^{
- // Clear the view, otherwise the last frame from this game will be displayed
- // briefly on the next game.
- [g_view bindDrawable];
- glClearColor(0, 0, 0, 1);
- glClear(GL_COLOR_BUFFER_BIT);
- [g_view display];
-
- glFinish();
-
+ g_initialized = false;
+
+ [GLContextClass clearCurrentContext];
+
+ dispatch_sync(dispatch_get_main_queue(),
+ ^{
#ifdef IOS
g_view.context = nil;
- [EAGLContext setCurrentContext:nil];
- g_context = nil;
#endif
+ [GLContextClass clearCurrentContext];
+ g_context = nil;
+ });
+}
+
+bool apple_gfx_ctx_bind_api(enum gfx_ctx_api api, unsigned major, unsigned minor)
+{
+ if (api != GLAPIType)
+ return false;
+
+
+ [GLContextClass clearCurrentContext];
+
+ dispatch_sync(dispatch_get_main_queue(),
+ ^{
+ [GLContextClass clearCurrentContext];
+
+#ifdef OSX
+ [g_context clearDrawable];
+ g_context = nil;
+ g_format = nil;
+
+ NSOpenGLPixelFormatAttribute attributes [] = {
+ NSOpenGLPFADoubleBuffer, // double buffered
+ NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)16, // 16 bit depth buffer
+ (major || minor) ? NSOpenGLPFAOpenGLProfile : 0, (major << 12) | (minor << 8),
+ (NSOpenGLPixelFormatAttribute)nil
+ };
+
+ g_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
+ g_context = [[NSOpenGLContext alloc] initWithFormat:g_format shareContext:nil];
+ g_context.view = g_view;
+#else
+ g_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
+ g_view.context = g_context;
+#endif
+
+ [g_context makeCurrentContext];
});
-#ifdef IOS
- [EAGLContext setCurrentContext:nil];
-#else
- [NSOpenGLContext clearCurrentContext];
-#endif
+ [g_context makeCurrentContext];
+ return true;
}
-void apple_flip_game_view()
-{
- if (--g_fast_forward_skips < 0)
- {
- dispatch_sync(dispatch_get_main_queue(), ^{
- [g_view display];
- });
- g_fast_forward_skips = g_is_syncing ? 0 : 3;
- }
-}
-
-void apple_set_game_view_sync(unsigned interval)
+void apple_gfx_ctx_swap_interval(unsigned interval)
{
#ifdef IOS // < No way to disable Vsync on iOS?
+ // Just skip presents so fast forward still works.
g_is_syncing = interval ? true : false;
g_fast_forward_skips = interval ? 0 : 3;
#elif defined(OSX)
GLint value = interval ? 1 : 0;
- [g_view.openGLContext setValues:&value forParameter:NSOpenGLCPSwapInterval];
+ [g_context setValues:&value forParameter:NSOpenGLCPSwapInterval];
#endif
}
-void apple_get_game_view_size(unsigned *width, unsigned *height)
+bool apple_gfx_ctx_set_video_mode(unsigned width, unsigned height, bool fullscreen)
{
- *width = g_view.bounds.size.width * g_screen_scale;
- *width = *width ? *width : 640;
+#ifdef OSX
+ dispatch_sync(dispatch_get_main_queue(),
+ ^{
+ // TODO: Sceen mode support
+
+ if (fullscreen && !g_has_went_fullscreen)
+ {
+ [g_view enterFullScreenMode:get_chosen_screen() withOptions:nil];
+ [NSCursor hide];
+ }
+ else if (!fullscreen && g_has_went_fullscreen)
+ {
+ [g_view exitFullScreenModeWithOptions:nil];
+ [g_view.window makeFirstResponder:g_view];
+ [NSCursor unhide];
+ }
+
+ g_has_went_fullscreen = fullscreen;
+ if (!g_has_went_fullscreen)
+ [g_view.window setContentSize:NSMakeSize(width, height)];
+ });
+#endif
+
+ // TODO: Maybe iOS users should be apple to show/hide the status bar here?
+
+ return true;
+}
+
+void apple_gfx_ctx_get_video_size(unsigned* width, unsigned* height)
+{
+ RAScreen* screen = get_chosen_screen();
+ CGRect size = g_initialized ? g_view.bounds : screen.bounds;
+
+ *width = CGRectGetWidth(size) * screen.scale;
+ *height = CGRectGetHeight(size) * screen.scale;
+}
+
+void apple_gfx_ctx_update_window_title(void)
+{
+#ifdef OSX
+ static char buf[128];
+ bool got_text = gfx_get_fps(buf, sizeof(buf), false);
+ static const char* const text = buf; // < Can't access buf directly in the block
- *height = g_view.bounds.size.height * g_screen_scale;
- *height = *height ? *height : 480;
+ if (got_text)
+ {
+ // NOTE: This could go bad if buf is updated again before this completes.
+ // If it poses a problem it should be changed to dispatch_sync.
+ dispatch_async(dispatch_get_main_queue(),
+ ^{
+ g_view.window.title = @(text);
+ });
+ }
+#endif
}
-void *apple_get_proc_address(const char *symbol_name)
+bool apple_gfx_ctx_has_focus(void)
{
-#ifdef IOS
- (void)symbol_name; // We don't need symbols above GLES2 on iOS.
- return NULL;
-#else
- CFStringRef symbol = CFStringCreateWithCString(kCFAllocatorDefault, symbol_name, kCFStringEncodingASCII);
- void *proc = CFBundleGetFunctionPointerForName(CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")),
- symbol);
- CFRelease(symbol);
- return proc;
-#endif
+ return APP_HAS_FOCUS;
+}
+
+void apple_gfx_ctx_swap_buffers()
+{
+ if (--g_fast_forward_skips < 0)
+ {
+ dispatch_sync(dispatch_get_main_queue(),
+ ^{
+ [g_view display];
+ });
+
+ g_fast_forward_skips = g_is_syncing ? 0 : 3;
+ }
+}
+
+gfx_ctx_proc_t apple_gfx_ctx_get_proc_address(const char *symbol_name)
+{
+ return (gfx_ctx_proc_t)CFBundleGetFunctionPointerForName(CFBundleGetBundleWithIdentifier(GLFrameworkID),
+ (__bridge CFStringRef)(@(symbol_name)));
}
#ifdef IOS
diff --git a/apple/RetroArch/RAModuleInfo.h b/apple/common/RAModuleInfo.h
similarity index 65%
rename from apple/RetroArch/RAModuleInfo.h
rename to apple/common/RAModuleInfo.h
index 5370b97f6a..39173ec473 100644
--- a/apple/RetroArch/RAModuleInfo.h
+++ b/apple/common/RAModuleInfo.h
@@ -22,15 +22,23 @@
#include "conf/config_file.h"
#include "core_info.h"
+extern NSArray* apple_get_modules();
+
@interface RAModuleInfo : NSObject
-@property (strong) NSString* path;
+@property NSString* path; // e.g. /path/to/corename_libretro.dylib
+@property NSString* baseName; // e.g. corename_libretro
@property core_info_t* info;
@property config_file_t* data;
-@property (strong) NSString* description;
+@property NSString* description; // Friendly name from config file, else just the filename
+@property NSString* customConfigFile; // Path where custom config file would reside
+@property NSString* configFile; // Path to effective config file
-+ (NSArray*)getModules;
- (bool)supportsFileAtPath:(NSString*)path;
+- (void)createCustomConfig;
+- (void)deleteCustomConfig;
+- (bool)hasCustomConfig;
+
@end
#endif
diff --git a/apple/RetroArch/RAModuleInfo.m b/apple/common/RAModuleInfo.m
similarity index 82%
rename from apple/RetroArch/RAModuleInfo.m
rename to apple/common/RAModuleInfo.m
index f4ffe70784..985cfcb9c7 100644
--- a/apple/RetroArch/RAModuleInfo.m
+++ b/apple/common/RAModuleInfo.m
@@ -22,27 +22,29 @@
static NSMutableArray* moduleList;
static core_info_list_t* coreList;
-@implementation RAModuleInfo
-+ (NSArray*)getModules
+NSArray* apple_get_modules()
{
if (!moduleList)
{
- coreList = get_core_info_list(apple_platform.corePath.UTF8String);
+ coreList = get_core_info_list(apple_platform.coreDirectory.UTF8String);
if (!coreList)
return nil;
-
- moduleList = [NSMutableArray arrayWithCapacity:coreList->count];
+ moduleList = [NSMutableArray arrayWithCapacity:coreList->count];
+
for (int i = 0; coreList && i < coreList->count; i ++)
{
core_info_t* core = &coreList->list[i];
RAModuleInfo* newInfo = [RAModuleInfo new];
- newInfo.path = [NSString stringWithUTF8String:core->path];
+ newInfo.path = @(core->path);
+ newInfo.baseName = newInfo.path.lastPathComponent.stringByDeletingPathExtension;
newInfo.info = core;
newInfo.data = core->data;
- newInfo.description = [NSString stringWithUTF8String:core->display_name];
+ newInfo.description = @(core->display_name);
+ newInfo.customConfigFile = [NSString stringWithFormat:@"%@/%@.cfg", apple_platform.configDirectory, newInfo.baseName];
+ newInfo.configFile = newInfo.hasCustomConfig ? newInfo.customConfigFile : apple_platform.globalConfigFile;
[moduleList addObject:newInfo];
}
@@ -56,9 +58,7 @@ static core_info_list_t* coreList;
return moduleList;
}
-- (void)dealloc
-{
-}
+@implementation RAModuleInfo
- (id)copyWithZone:(NSZone *)zone
{
@@ -70,6 +70,23 @@ static core_info_list_t* coreList;
return does_core_support_file(self.info, path.UTF8String);
}
+- (void)createCustomConfig
+{
+ if (!self.hasCustomConfig)
+ [NSFileManager.defaultManager copyItemAtPath:apple_platform.globalConfigFile toPath:self.customConfigFile error:nil];
+}
+
+- (void)deleteCustomConfig
+{
+ if (self.hasCustomConfig)
+ [NSFileManager.defaultManager removeItemAtPath:self.customConfigFile error:nil];
+}
+
+- (bool)hasCustomConfig
+{
+ return path_file_exists(self.customConfigFile.UTF8String);
+}
+
@end
#ifdef IOS
@@ -114,7 +131,7 @@ static NSString* build_string_pair(NSString* stringA, NSString* stringB)
for (int i = 0; i < firmwareCount; i ++)
{
NSString* path = objc_get_value_from_config(_data.data, [NSString stringWithFormat:@"firmware%d_path", i + 1], @"Unspecified");
- path = [path stringByReplacingOccurrencesOfString:@"%sysdir%" withString:RetroArch_iOS.get.systemDirectory];
+ path = [path stringByReplacingOccurrencesOfString:@"%sysdir%" withString:[RetroArch_iOS get].systemDirectory];
[firmwareSection addObject:build_string_pair(objc_get_value_from_config(_data.data, [NSString stringWithFormat:@"firmware%d_desc", i + 1], @"Unspecified"), path)];
}
diff --git a/apple/RetroArch/RetroArch_Apple.h b/apple/common/RetroArch_Apple.h
similarity index 53%
rename from apple/RetroArch/RetroArch_Apple.h
rename to apple/common/RetroArch_Apple.h
index 5302d3a4c2..b8616ae78e 100644
--- a/apple/RetroArch/RetroArch_Apple.h
+++ b/apple/common/RetroArch_Apple.h
@@ -21,71 +21,42 @@
#import
#import "RAModuleInfo.h"
-void apple_run_core(RAModuleInfo* core, const char* file);
+#define GSEVENT_TYPE_KEYDOWN 10
+#define GSEVENT_TYPE_KEYUP 11
@protocol RetroArch_Platform
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file;
- (void)unloadingCore:(RAModuleInfo*)core;
-- (NSString*)retroarchConfigPath;
-- (NSString*)corePath;
+
+- (NSString*)configDirectory; // < This returns the directory that contains retroarch.cfg and other custom configs
+- (NSString*)globalConfigFile; // < This is the full path to retroarch.cfg
+- (NSString*)coreDirectory; // < This is the default path to where libretro cores are installed
@end
+#ifdef IOS
+#import "../iOS/platform.h"
+#elif defined(OSX)
+#import "../OSX/platform.h"
+#endif
+
+extern char** apple_argv;
+extern bool apple_is_paused;
+extern bool apple_is_running;
+extern bool apple_use_tv_mode;
+extern RAModuleInfo* apple_core;
+
extern id apple_platform;
-#ifdef IOS
+// main.m
+enum basic_event_t { RESET = 1, LOAD_STATE = 2, SAVE_STATE = 3, QUIT = 4 };
+extern void apple_event_basic_command(void* userdata);
+extern void apple_event_set_state_slot(void* userdata);
+extern void apple_event_show_rgui(void* userdata);
-// RAGameView.m
-@interface RAGameView : UIViewController
-+ (RAGameView*)get;
-- (void)openPauseMenu;
-- (void)closePauseMenu;
-
-- (void)suspend;
-- (void)resume;
-@end
-
-@interface RetroArch_iOS : UINavigationController
-
-+ (RetroArch_iOS*)get;
-
-- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file;
-- (void)unloadingCore:(RAModuleInfo*)core;
-- (NSString*)retroarchConfigPath;
-
-- (void)refreshConfig;
-- (void)refreshSystemConfig;
-
-@property (strong, nonatomic) NSString* documentsDirectory; // e.g. /var/mobile/Documents
-@property (strong, nonatomic) NSString* systemDirectory; // e.g. /var/mobile/Documents/.RetroArch
-@property (strong, nonatomic) NSString* systemConfigPath; // e.g. /var/mobile/Documents/.RetroArch/frontend.cfg
-
-@end
-
-#elif defined(OSX)
-
-#import
-
-@interface RAGameView : NSOpenGLView
-
-+ (RAGameView*)get;
-- (void)display;
-
-@end
-
-@interface RetroArch_OSX : NSObject
-{
-@public
- NSWindow IBOutlet *window;
-}
-
-+ (RetroArch_OSX*)get;
-
-- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file;
-- (void)unloadingCore:(RAModuleInfo*)core;
-
-@end
-
-#endif
+extern void apple_refresh_config();
+extern void apple_enter_stasis();
+extern void apple_exit_stasis(bool reload_config);
+extern void apple_run_core(RAModuleInfo* core, const char* file);
// utility.m
extern void apple_display_alert(NSString* message, NSString* title);
@@ -93,4 +64,7 @@ extern void objc_clear_config_hack();
extern bool path_make_and_check_directory(const char* path, mode_t mode, int amode);
extern NSString* objc_get_value_from_config(config_file_t* config, NSString* name, NSString* defaultValue);
+// frontend/platform/platform_apple.c
+extern void apple_frontend_post_event(void (*fn)(void*), void* userdata);
+
#endif
diff --git a/apple/RetroArch/apple_input.c b/apple/common/apple_input.c
similarity index 72%
rename from apple/RetroArch/apple_input.c
rename to apple/common/apple_input.c
index 07a1bdecfa..152acb13a0 100644
--- a/apple/RetroArch/apple_input.c
+++ b/apple/common/apple_input.c
@@ -22,14 +22,14 @@
#include "general.h"
#include "driver.h"
+#include "keycode.inc"
+
extern const rarch_joypad_driver_t apple_joypad;
static const rarch_joypad_driver_t* const g_joydriver = &apple_joypad;
apple_input_data_t g_current_input_data;
apple_input_data_t g_polled_input_data;
-static const struct rarch_key_map rarch_key_map_hidusage[];
-
#ifdef OSX // Taken from https://github.com/depp/keycode, check keycode.h for license
const unsigned char MAC_NATIVE_TO_HID[128] = {
4, 22, 7, 9, 11, 10, 29, 27, 6, 25,255, 5, 20, 26, 8, 21,
@@ -101,6 +101,42 @@ void apple_input_handle_key_event(unsigned keycode, bool down)
g_current_input_data.keys[keycode] = down;
}
+
+int32_t apple_input_find_any_key()
+{
+ for (int i = 0; apple_key_name_map[i].hid_id; i++)
+ if (g_current_input_data.keys[apple_key_name_map[i].hid_id])
+ return apple_key_name_map[i].hid_id;
+
+ return 0;
+}
+
+int32_t apple_input_find_any_button(uint32_t port)
+{
+ uint32_t buttons = g_current_input_data.pad_buttons[port] |
+ ((port == 0) ? apple_input_get_icade_buttons() : 0);
+
+ if (g_current_input_data.pad_buttons[port])
+ for (int i = 0; i != 32; i ++)
+ if (buttons & (1 << i))
+ return i;
+
+ return -1;
+}
+
+int32_t apple_input_find_any_axis(uint32_t port)
+{
+ for (int i = 0; i < 4; i++)
+ {
+ int16_t value = g_current_input_data.pad_axis[port][i];
+
+ if (abs(value) > 0x4000)
+ return (value < 0) ? -(i + 1) : i + 1;
+ }
+
+ return 0;
+}
+
// Game thread interface
static bool apple_key_pressed(enum retro_key key)
{
@@ -118,7 +154,7 @@ static bool apple_is_pressed(unsigned port_num, const struct retro_keybind *bind
// Exported input driver
static void *apple_input_init(void)
{
- input_init_keyboard_lut(rarch_key_map_hidusage);
+ input_init_keyboard_lut(apple_key_map_hidusage);
memset(&g_polled_input_data, 0, sizeof(g_polled_input_data));
return (void*)-1;
}
@@ -273,150 +309,3 @@ const input_driver_t input_apple = {
apple_input_set_keybinds,
"apple_input",
};
-
-
-// Key table
-#include "keycode.h"
-static const struct rarch_key_map rarch_key_map_hidusage[] = {
- { KEY_Delete, RETROK_BACKSPACE },
- { KEY_Tab, RETROK_TAB },
-// RETROK_CLEAR },
- { KEY_Enter, RETROK_RETURN },
- { KEY_Pause, RETROK_PAUSE },
- { KEY_Escape, RETROK_ESCAPE },
- { KEY_Space, RETROK_SPACE },
-// RETROK_EXCLAIM },
-// RETROK_QUOTEDBL },
-// RETROK_HASH },
-// RETROK_DOLLAR },
-// RETROK_AMPERSAND },
- { KEY_Quote, RETROK_QUOTE },
-// RETROK_LEFTPAREN },
-// RETROK_RIGHTPAREN },
-// RETROK_ASTERISK },
-// RETROK_PLUS },
- { KEY_Comma, RETROK_COMMA },
- { KEY_Minus, RETROK_MINUS },
- { KEY_Period, RETROK_PERIOD },
- { KEY_Slash, RETROK_SLASH },
- { KEY_0, RETROK_0 },
- { KEY_1, RETROK_1 },
- { KEY_2, RETROK_2 },
- { KEY_3, RETROK_3 },
- { KEY_4, RETROK_4 },
- { KEY_5, RETROK_5 },
- { KEY_6, RETROK_6 },
- { KEY_7, RETROK_7 },
- { KEY_8, RETROK_8 },
- { KEY_9, RETROK_9 },
-// RETROK_COLON },
- { KEY_Semicolon, RETROK_SEMICOLON },
-// RETROK_LESS },
- { KEY_Equals, RETROK_EQUALS },
-// RETROK_GREATER },
-// RETROK_QUESTION },
-// RETROK_AT },
- { KEY_LeftBracket, RETROK_LEFTBRACKET },
- { KEY_Backslash, RETROK_BACKSLASH },
- { KEY_RightBracket, RETROK_RIGHTBRACKET },
-// RETROK_CARET },
-// RETROK_UNDERSCORE },
- { KEY_Grave, RETROK_BACKQUOTE },
- { KEY_A, RETROK_a },
- { KEY_B, RETROK_b },
- { KEY_C, RETROK_c },
- { KEY_D, RETROK_d },
- { KEY_E, RETROK_e },
- { KEY_F, RETROK_f },
- { KEY_G, RETROK_g },
- { KEY_H, RETROK_h },
- { KEY_I, RETROK_i },
- { KEY_J, RETROK_j },
- { KEY_K, RETROK_k },
- { KEY_L, RETROK_l },
- { KEY_M, RETROK_m },
- { KEY_N, RETROK_n },
- { KEY_O, RETROK_o },
- { KEY_P, RETROK_p },
- { KEY_Q, RETROK_q },
- { KEY_R, RETROK_r },
- { KEY_S, RETROK_s },
- { KEY_T, RETROK_t },
- { KEY_U, RETROK_u },
- { KEY_V, RETROK_v },
- { KEY_W, RETROK_w },
- { KEY_X, RETROK_x },
- { KEY_Y, RETROK_y },
- { KEY_Z, RETROK_z },
- { KEY_DeleteForward, RETROK_DELETE },
-
- { KP_0, RETROK_KP0 },
- { KP_1, RETROK_KP1 },
- { KP_2, RETROK_KP2 },
- { KP_3, RETROK_KP3 },
- { KP_4, RETROK_KP4 },
- { KP_5, RETROK_KP5 },
- { KP_6, RETROK_KP6 },
- { KP_7, RETROK_KP7 },
- { KP_8, RETROK_KP8 },
- { KP_9, RETROK_KP9 },
- { KP_Point, RETROK_KP_PERIOD },
- { KP_Divide, RETROK_KP_DIVIDE },
- { KP_Multiply, RETROK_KP_MULTIPLY },
- { KP_Subtract, RETROK_KP_MINUS },
- { KP_Add, RETROK_KP_PLUS },
- { KP_Enter, RETROK_KP_ENTER },
- { KP_Equals, RETROK_KP_EQUALS },
-
- { KEY_Up, RETROK_UP },
- { KEY_Down, RETROK_DOWN },
- { KEY_Right, RETROK_RIGHT },
- { KEY_Left, RETROK_LEFT },
- { KEY_Insert, RETROK_INSERT },
- { KEY_Home, RETROK_HOME },
- { KEY_End, RETROK_END },
- { KEY_PageUp, RETROK_PAGEUP },
- { KEY_PageDown, RETROK_PAGEDOWN },
-
- { KEY_F1, RETROK_F1 },
- { KEY_F2, RETROK_F2 },
- { KEY_F3, RETROK_F3 },
- { KEY_F4, RETROK_F4 },
- { KEY_F5, RETROK_F5 },
- { KEY_F6, RETROK_F6 },
- { KEY_F7, RETROK_F7 },
- { KEY_F8, RETROK_F8 },
- { KEY_F9, RETROK_F9 },
- { KEY_F10, RETROK_F10 },
- { KEY_F11, RETROK_F11 },
- { KEY_F12, RETROK_F12 },
- { KEY_F13, RETROK_F13 },
- { KEY_F14, RETROK_F14 },
- { KEY_F15, RETROK_F15 },
-
-// RETROK_NUMLOCK },
- { KEY_CapsLock, RETROK_CAPSLOCK },
-// RETROK_SCROLLOCK },
- { KEY_RightShift, RETROK_RSHIFT },
- { KEY_LeftShift, RETROK_LSHIFT },
- { KEY_RightControl, RETROK_RCTRL },
- { KEY_LeftControl, RETROK_LCTRL },
- { KEY_RightAlt, RETROK_RALT },
- { KEY_LeftAlt, RETROK_LALT },
- { KEY_RightGUI, RETROK_RMETA },
- { KEY_LeftGUI, RETROK_RMETA },
-// RETROK_LSUPER },
-// RETROK_RSUPER },
-// RETROK_MODE },
-// RETROK_COMPOSE },
-
-// RETROK_HELP },
- { KEY_PrintScreen, RETROK_PRINT },
-// RETROK_SYSREQ },
-// RETROK_BREAK },
- { KEY_Menu, RETROK_MENU },
-// RETROK_POWER },
-// RETROK_EURO },
-// RETROK_UNDO },
- { 0, RETROK_UNKNOWN }
-};
diff --git a/apple/RetroArch/apple_input.h b/apple/common/apple_input.h
similarity index 90%
rename from apple/RetroArch/apple_input.h
rename to apple/common/apple_input.h
index 4a1ee13788..8d95746597 100644
--- a/apple/RetroArch/apple_input.h
+++ b/apple/common/apple_input.h
@@ -50,4 +50,8 @@ void apple_input_enable_icade(bool on);
uint32_t apple_input_get_icade_buttons();
void apple_input_handle_key_event(unsigned keycode, bool down);
+extern int32_t apple_input_find_any_key();
+extern int32_t apple_input_find_any_button(uint32_t port);
+extern int32_t apple_input_find_any_axis(uint32_t port);
+
#endif
diff --git a/apple/RetroArch/apple_joypad.c b/apple/common/apple_joypad.c
similarity index 87%
rename from apple/RetroArch/apple_joypad.c
rename to apple/common/apple_joypad.c
index 312f245b43..96ed6812ba 100644
--- a/apple/RetroArch/apple_joypad.c
+++ b/apple/common/apple_joypad.c
@@ -17,16 +17,17 @@
#include "general.h"
#ifdef IOS
-#include "../iOS/input/BTStack/btdynamic.c"
-#include "../iOS/input/BTStack/wiimote.c"
-#include "../iOS/input/BTStack/btpad.c"
-#include "../iOS/input/BTStack/btpad_ps3.c"
-#include "../iOS/input/BTStack/btpad_wii.c"
-#include "../iOS/input/BTStack/btpad_queue.c"
+#include "apple/iOS/bluetooth/btdynamic.c"
+#include "apple/iOS/bluetooth/btpad.c"
+#include "apple/iOS/bluetooth/btpad_queue.c"
#elif defined(OSX)
#include "../OSX/hid_pad.c"
#endif
+#include "apple/common/hidpad/wiimote.c"
+#include "apple/common/hidpad/hidpad_ps3.c"
+#include "apple/common/hidpad/hidpad_wii.c"
+
static bool apple_joypad_init(void)
{
@@ -56,7 +57,7 @@ static bool apple_joypad_button(unsigned port, uint16_t joykey)
static int16_t apple_joypad_axis(unsigned port, uint32_t joyaxis)
{
- if (joyaxis == AXIS_NONE || port != 0)
+ if (joyaxis == AXIS_NONE)
return 0;
int16_t val = 0;
diff --git a/apple/common/hidpad/hidpad.h b/apple/common/hidpad/hidpad.h
new file mode 100644
index 0000000000..4002c8d060
--- /dev/null
+++ b/apple/common/hidpad/hidpad.h
@@ -0,0 +1,32 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2013 - Jason Fetters
+ *
+ * RetroArch is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with RetroArch.
+ * If not, see .
+ */
+
+#ifndef __IOS_RARCH_HIDPAD_H__
+#define __IOS_RARCH_HIDPAD_H__
+
+struct hidpad_connection;
+void hidpad_send_control(struct hidpad_connection* connection, uint8_t* data, size_t size);
+
+struct hidpad_interface
+{
+ void* (*connect)(struct hidpad_connection* connection, uint32_t slot);
+ void (*disconnect)(void* device);
+ void (*packet_handler)(void* device, uint8_t *packet, uint16_t size);
+};
+
+extern struct hidpad_interface hidpad_wii;
+extern struct hidpad_interface hidpad_ps3;
+
+#endif
diff --git a/apple/iOS/input/BTStack/btpad_ps3.c b/apple/common/hidpad/hidpad_ps3.c
similarity index 56%
rename from apple/iOS/input/BTStack/btpad_ps3.c
rename to apple/common/hidpad/hidpad_ps3.c
index e2079ef6ea..d68411269d 100644
--- a/apple/iOS/input/BTStack/btpad_ps3.c
+++ b/apple/common/hidpad/hidpad_ps3.c
@@ -18,26 +18,23 @@
#include
#include "boolean.h"
-#include "../../../RetroArch/rarch_wrapper.h"
+#include "apple/common/rarch_wrapper.h"
-#include "btdynamic.h"
-#include "btpad.h"
+#include "hidpad.h"
-struct btpad_ps3_data
+struct hidpad_ps3_data
{
+ struct hidpad_connection* connection;
+
uint8_t data[512];
-
- bd_addr_t address;
- uint32_t handle;
- uint32_t channels[2];
-
+
uint32_t slot;
bool have_led;
};
-static void btpad_ps3_send_control(struct btpad_ps3_data* device)
+static void hidpad_ps3_send_control(struct hidpad_ps3_data* device)
{
- // TODO: Can this be modified to turn of motion tracking?
+ // TODO: Can this be modified to turn off motion tracking?
static uint8_t report_buffer[] = {
0x52, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00,
@@ -52,35 +49,38 @@ static void btpad_ps3_send_control(struct btpad_ps3_data* device)
};
report_buffer[11] = 1 << ((device->slot % 4) + 1);
- bt_send_l2cap_ptr(device->channels[0], report_buffer, sizeof(report_buffer));
+#ifdef IOS
+ hidpad_send_control(device->connection, report_buffer, sizeof(report_buffer));
+#else
+ hidpad_send_control(device->connection, report_buffer + 1, sizeof(report_buffer) - 1);
+#endif
}
-static void* btpad_ps3_connect(const btpad_connection_t* connection)
+static void* hidpad_ps3_connect(struct hidpad_connection* connection, uint32_t slot)
{
- struct btpad_ps3_data* device = malloc(sizeof(struct btpad_ps3_data));
+ struct hidpad_ps3_data* device = malloc(sizeof(struct hidpad_ps3_data));
memset(device, 0, sizeof(*device));
-
- memcpy(device->address, connection->address, BD_ADDR_LEN);
- device->handle = connection->handle;
- device->channels[0] = connection->channels[0];
- device->channels[1] = connection->channels[1];
- device->slot = connection->slot;
+ device->connection = connection;
+ device->slot = slot;
// Magic packet to start reports
+#ifdef IOS
static uint8_t data[] = {0x53, 0xF4, 0x42, 0x03, 0x00, 0x00};
- bt_send_l2cap_ptr(device->channels[0], data, 6);
+ hidpad_send_control(device->connection, data, 6);
+#endif
// Without this the digital buttons won't be reported
- btpad_ps3_send_control(device);
+ hidpad_ps3_send_control(device);
return device;
}
-static void btpad_ps3_disconnect(struct btpad_ps3_data* device)
+static void hidpad_ps3_disconnect(struct hidpad_ps3_data* device)
{
+ free(device);
}
-static uint32_t btpad_ps3_get_buttons(struct btpad_ps3_data* device)
+static uint32_t hidpad_ps3_get_buttons(struct hidpad_ps3_data* device)
{
#define KEY(X) RETRO_DEVICE_ID_JOYPAD_##X
static const uint32_t button_mapping[17] =
@@ -102,7 +102,7 @@ static uint32_t btpad_ps3_get_buttons(struct btpad_ps3_data* device)
return result;
}
-static int16_t btpad_ps3_get_axis(struct btpad_ps3_data* device, unsigned axis)
+static int16_t hidpad_ps3_get_axis(struct hidpad_ps3_data* device, unsigned axis)
{
if (axis < 4)
{
@@ -114,28 +114,28 @@ static int16_t btpad_ps3_get_axis(struct btpad_ps3_data* device, unsigned axis)
return 0;
}
-static void btpad_ps3_packet_handler(struct btpad_ps3_data* device, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
+static void hidpad_ps3_packet_handler(struct hidpad_ps3_data* device, uint8_t *packet, uint16_t size)
{
- if (packet_type == L2CAP_DATA_PACKET && packet[0] == 0xA1)
+ if (!device->have_led)
{
- if (!device->have_led)
- {
- btpad_ps3_send_control(device);
- device->have_led = true;
- }
-
- memcpy(device->data, packet, size);
- g_current_input_data.pad_buttons[device->slot] = btpad_ps3_get_buttons(device);
- for (int i = 0; i < 4; i ++)
- g_current_input_data.pad_axis[device->slot][i] = btpad_ps3_get_axis(device, i);
+ hidpad_ps3_send_control(device);
+ device->have_led = true;
}
+
+#ifdef IOS
+ memcpy(device->data, packet, size);
+#else
+ memcpy(device->data + 1, packet, size);
+#endif
+
+ g_current_input_data.pad_buttons[device->slot] = hidpad_ps3_get_buttons(device);
+ for (int i = 0; i < 4; i ++)
+ g_current_input_data.pad_axis[device->slot][i] = hidpad_ps3_get_axis(device, i);
}
-struct btpad_interface btpad_ps3 =
+struct hidpad_interface hidpad_ps3 =
{
- (void*)&btpad_ps3_connect,
- (void*)&btpad_ps3_disconnect,
- (void*)&btpad_ps3_get_buttons,
- (void*)&btpad_ps3_get_axis,
- (void*)&btpad_ps3_packet_handler
+ (void*)&hidpad_ps3_connect,
+ (void*)&hidpad_ps3_disconnect,
+ (void*)&hidpad_ps3_packet_handler
};
diff --git a/apple/common/hidpad/hidpad_wii.c b/apple/common/hidpad/hidpad_wii.c
new file mode 100644
index 0000000000..5d54bd4860
--- /dev/null
+++ b/apple/common/hidpad/hidpad_wii.c
@@ -0,0 +1,113 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2013 - Jason Fetters
+ *
+ * RetroArch is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with RetroArch.
+ * If not, see .
+ */
+
+#include
+#include
+#include
+
+#include "boolean.h"
+#include "apple/common/rarch_wrapper.h"
+
+#include "wiimote.h"
+#include "hidpad.h"
+
+static void* hidpad_wii_connect(struct hidpad_connection* connection, uint32_t slot)
+{
+ struct wiimote_t* device = malloc(sizeof(struct wiimote_t));
+ memset(device, 0, sizeof(struct wiimote_t));
+
+ device->connection = connection;
+ device->unid = slot;
+ device->state = WIIMOTE_STATE_CONNECTED;
+ device->exp.type = EXP_NONE;
+
+ wiimote_handshake(device, -1, NULL, -1);
+
+ return device;
+}
+
+static void hidpad_wii_disconnect(struct wiimote_t* device)
+{
+ free(device);
+}
+
+static int16_t hidpad_wii_get_axis(struct wiimote_t* device, unsigned axis)
+{
+/* TODO
+ if (device->.exp.type == EXP_CLASSIC)
+ {
+ switch (axis)
+ {
+ case 0: return device->wiimote.exp.classic.ljs.rx * 0x7FFF;
+ case 1: return device->wiimote.exp.classic.ljs.ry * 0x7FFF;
+ case 2: return device->wiimote.exp.classic.rjs.rx * 0x7FFF;
+ case 3: return device->wiimote.exp.classic.rjs.ry * 0x7FFF;
+ default: return 0;
+ }
+ }
+*/
+
+ return 0;
+}
+
+static void hidpad_wii_packet_handler(struct wiimote_t* device, uint8_t *packet, uint16_t size)
+{
+#ifdef IOS
+ byte* msg = packet + 2;
+ switch (packet[1])
+#else
+ byte* msg = packet + 1;
+ switch (packet[0])
+#endif
+ {
+ case WM_RPT_BTN:
+ {
+ wiimote_pressed_buttons(device, msg);
+ break;
+ }
+
+ case WM_RPT_READ:
+ {
+ wiimote_pressed_buttons(device, msg);
+ wiimote_handshake(device, WM_RPT_READ, msg + 5, ((msg[2] & 0xF0) >> 4) + 1);
+ break;
+ }
+
+ case WM_RPT_CTRL_STATUS:
+ {
+ wiimote_pressed_buttons(device, msg);
+ wiimote_handshake(device,WM_RPT_CTRL_STATUS,msg,-1);
+ break;
+ }
+
+ case WM_RPT_BTN_EXP:
+ {
+ wiimote_pressed_buttons(device, msg);
+ wiimote_handle_expansion(device, msg+2);
+ break;
+ }
+ }
+
+ g_current_input_data.pad_buttons[device->unid] = device->btns | (device->exp.classic.btns << 16);
+ for (int i = 0; i < 4; i ++)
+ g_current_input_data.pad_axis[device->unid][i] = hidpad_wii_get_axis(device, i);
+}
+
+struct hidpad_interface hidpad_wii =
+{
+ (void*)&hidpad_wii_connect,
+ (void*)&hidpad_wii_disconnect,
+ (void*)&hidpad_wii_packet_handler
+};
diff --git a/apple/iOS/input/BTStack/wiimote.c b/apple/common/hidpad/wiimote.c
similarity index 99%
rename from apple/iOS/input/BTStack/wiimote.c
rename to apple/common/hidpad/wiimote.c
index c168ce2ca2..35dadfa65a 100644
--- a/apple/iOS/input/BTStack/wiimote.c
+++ b/apple/common/hidpad/wiimote.c
@@ -45,8 +45,6 @@
#include
#include "boolean.h"
-#include "btdynamic.h"
-#include "btstack/btstack.h"
#include "wiimote.h"
int wiimote_send(struct wiimote_t* wm, byte report_type, byte* msg, int len);
@@ -360,7 +358,11 @@ int wiimote_send(struct wiimote_t* wm, byte report_type, byte* msg, int len)
printf("\n");
#endif
- bt_send_l2cap_ptr( wm->c_source_cid, buf, len+2);
+#ifdef IOS
+ hidpad_send_control(wm->connection, buf, len + 2);
+#else
+ hidpad_send_control(wm->connection, buf + 1, len + 1);
+#endif
return 1;
}
diff --git a/apple/iOS/input/BTStack/wiimote.h b/apple/common/hidpad/wiimote.h
similarity index 98%
rename from apple/iOS/input/BTStack/wiimote.h
rename to apple/common/hidpad/wiimote.h
index b6e46a0dd3..c2d985f52e 100644
--- a/apple/iOS/input/BTStack/wiimote.h
+++ b/apple/common/hidpad/wiimote.h
@@ -41,7 +41,7 @@
#ifndef __WIIMOTE_H__
#define __WIIMOTE_H__
-#include "btstack/utils.h"
+#include "hidpad.h"
#if defined(__cplusplus)
extern "C" {
@@ -232,11 +232,7 @@ extern "C" {
typedef struct wiimote_t {
int unid; /**< user specified id */
- uint16_t wiiMoteConHandle;
- uint16_t i_source_cid;
- uint16_t c_source_cid;
- bd_addr_t addr;
-
+ struct hidpad_connection* connection;
int state; /**< various state flags */
byte leds; /**< currently lit leds */
float battery_level; /**< battery level */
diff --git a/apple/RetroArch/keycode.h b/apple/common/keycode.h
similarity index 91%
rename from apple/RetroArch/keycode.h
rename to apple/common/keycode.h
index e24fe023d4..f0b8a1219a 100644
--- a/apple/RetroArch/keycode.h
+++ b/apple/common/keycode.h
@@ -153,4 +153,21 @@ enum {
KEY_RightAlt = 230,
KEY_RightGUI = 231
};
+
+//
+
+#include "input/input_common.h" // < For rarch_key_map
+
+struct apple_key_name_map_entry
+{
+ const char* const keyname;
+ const uint32_t hid_id;
+};
+
+extern const struct apple_key_name_map_entry apple_key_name_map[];
+extern const struct rarch_key_map apple_key_map_hidusage[];
+
+
+const char* apple_keycode_hidusage_to_name(uint32_t hid_usage);
+
#endif
diff --git a/apple/common/keycode.inc b/apple/common/keycode.inc
new file mode 100644
index 0000000000..f9d7363113
--- /dev/null
+++ b/apple/common/keycode.inc
@@ -0,0 +1,222 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2013 - Jason Fetters
+ *
+ * RetroArch is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with RetroArch.
+ * If not, see .
+ */
+
+#include "keycode.h"
+
+const struct apple_key_name_map_entry apple_key_name_map[] =
+{
+ { "left", KEY_Left }, { "right", KEY_Right },
+ { "up", KEY_Up }, { "down", KEY_Down },
+ { "enter", KEY_Enter }, { "kp_enter", KP_Enter },
+ { "space", KEY_Space }, { "tab", KEY_Tab },
+ { "shift", KEY_LeftShift }, { "rshift", KEY_RightShift },
+ { "ctrl", KEY_LeftControl }, { "alt", KEY_LeftAlt },
+ { "escape", KEY_Escape }, { "backspace", KEY_DeleteForward },
+ { "backquote", KEY_Grave }, { "pause", KEY_Pause },
+
+ { "f1", KEY_F1 }, { "f2", KEY_F2 },
+ { "f3", KEY_F3 }, { "f4", KEY_F4 },
+ { "f5", KEY_F5 }, { "f6", KEY_F6 },
+ { "f7", KEY_F7 }, { "f8", KEY_F8 },
+ { "f9", KEY_F9 }, { "f10", KEY_F10 },
+ { "f11", KEY_F11 }, { "f12", KEY_F12 },
+
+ { "num0", KEY_0 }, { "num1", KEY_1 },
+ { "num2", KEY_2 }, { "num3", KEY_3 },
+ { "num4", KEY_4 }, { "num5", KEY_5 },
+ { "num6", KEY_6 }, { "num7", KEY_7 },
+ { "num8", KEY_8 }, { "num9", KEY_9 },
+
+ { "insert", KEY_Insert }, { "del", KEY_DeleteForward },
+ { "home", KEY_Home }, { "end", KEY_End },
+ { "pageup", KEY_PageUp }, { "pagedown", KEY_PageDown },
+
+ { "add", KP_Add }, { "subtract", KP_Subtract },
+ { "multiply", KP_Multiply }, { "divide", KP_Divide },
+ { "keypad0", KP_0 }, { "keypad1", KP_1 },
+ { "keypad2", KP_2 }, { "keypad3", KP_3 },
+ { "keypad4", KP_4 }, { "keypad5", KP_5 },
+ { "keypad6", KP_6 }, { "keypad7", KP_7 },
+ { "keypad8", KP_8 }, { "keypad9", KP_9 },
+
+ { "period", KEY_Period }, { "capslock", KEY_CapsLock },
+ { "numlock", KP_NumLock }, { "print_screen", KEY_PrintScreen },
+ { "scroll_lock", KEY_ScrollLock },
+
+ { "a", KEY_A }, { "b", KEY_B }, { "c", KEY_C }, { "d", KEY_D },
+ { "e", KEY_E }, { "f", KEY_F }, { "g", KEY_G }, { "h", KEY_H },
+ { "i", KEY_I }, { "j", KEY_J }, { "k", KEY_K }, { "l", KEY_L },
+ { "m", KEY_M }, { "n", KEY_N }, { "o", KEY_O }, { "p", KEY_P },
+ { "q", KEY_Q }, { "r", KEY_R }, { "s", KEY_S }, { "t", KEY_T },
+ { "u", KEY_U }, { "v", KEY_V }, { "w", KEY_W }, { "x", KEY_X },
+ { "y", KEY_Y }, { "z", KEY_Z },
+
+ { "nul", 0x00},
+};
+
+const struct rarch_key_map apple_key_map_hidusage[] =
+{
+ { KEY_Delete, RETROK_BACKSPACE },
+ { KEY_Tab, RETROK_TAB },
+// RETROK_CLEAR },
+ { KEY_Enter, RETROK_RETURN },
+ { KEY_Pause, RETROK_PAUSE },
+ { KEY_Escape, RETROK_ESCAPE },
+ { KEY_Space, RETROK_SPACE },
+// RETROK_EXCLAIM },
+// RETROK_QUOTEDBL },
+// RETROK_HASH },
+// RETROK_DOLLAR },
+// RETROK_AMPERSAND },
+ { KEY_Quote, RETROK_QUOTE },
+// RETROK_LEFTPAREN },
+// RETROK_RIGHTPAREN },
+// RETROK_ASTERISK },
+// RETROK_PLUS },
+ { KEY_Comma, RETROK_COMMA },
+ { KEY_Minus, RETROK_MINUS },
+ { KEY_Period, RETROK_PERIOD },
+ { KEY_Slash, RETROK_SLASH },
+ { KEY_0, RETROK_0 },
+ { KEY_1, RETROK_1 },
+ { KEY_2, RETROK_2 },
+ { KEY_3, RETROK_3 },
+ { KEY_4, RETROK_4 },
+ { KEY_5, RETROK_5 },
+ { KEY_6, RETROK_6 },
+ { KEY_7, RETROK_7 },
+ { KEY_8, RETROK_8 },
+ { KEY_9, RETROK_9 },
+// RETROK_COLON },
+ { KEY_Semicolon, RETROK_SEMICOLON },
+// RETROK_LESS },
+ { KEY_Equals, RETROK_EQUALS },
+// RETROK_GREATER },
+// RETROK_QUESTION },
+// RETROK_AT },
+ { KEY_LeftBracket, RETROK_LEFTBRACKET },
+ { KEY_Backslash, RETROK_BACKSLASH },
+ { KEY_RightBracket, RETROK_RIGHTBRACKET },
+// RETROK_CARET },
+// RETROK_UNDERSCORE },
+ { KEY_Grave, RETROK_BACKQUOTE },
+ { KEY_A, RETROK_a },
+ { KEY_B, RETROK_b },
+ { KEY_C, RETROK_c },
+ { KEY_D, RETROK_d },
+ { KEY_E, RETROK_e },
+ { KEY_F, RETROK_f },
+ { KEY_G, RETROK_g },
+ { KEY_H, RETROK_h },
+ { KEY_I, RETROK_i },
+ { KEY_J, RETROK_j },
+ { KEY_K, RETROK_k },
+ { KEY_L, RETROK_l },
+ { KEY_M, RETROK_m },
+ { KEY_N, RETROK_n },
+ { KEY_O, RETROK_o },
+ { KEY_P, RETROK_p },
+ { KEY_Q, RETROK_q },
+ { KEY_R, RETROK_r },
+ { KEY_S, RETROK_s },
+ { KEY_T, RETROK_t },
+ { KEY_U, RETROK_u },
+ { KEY_V, RETROK_v },
+ { KEY_W, RETROK_w },
+ { KEY_X, RETROK_x },
+ { KEY_Y, RETROK_y },
+ { KEY_Z, RETROK_z },
+ { KEY_DeleteForward, RETROK_DELETE },
+
+ { KP_0, RETROK_KP0 },
+ { KP_1, RETROK_KP1 },
+ { KP_2, RETROK_KP2 },
+ { KP_3, RETROK_KP3 },
+ { KP_4, RETROK_KP4 },
+ { KP_5, RETROK_KP5 },
+ { KP_6, RETROK_KP6 },
+ { KP_7, RETROK_KP7 },
+ { KP_8, RETROK_KP8 },
+ { KP_9, RETROK_KP9 },
+ { KP_Point, RETROK_KP_PERIOD },
+ { KP_Divide, RETROK_KP_DIVIDE },
+ { KP_Multiply, RETROK_KP_MULTIPLY },
+ { KP_Subtract, RETROK_KP_MINUS },
+ { KP_Add, RETROK_KP_PLUS },
+ { KP_Enter, RETROK_KP_ENTER },
+ { KP_Equals, RETROK_KP_EQUALS },
+
+ { KEY_Up, RETROK_UP },
+ { KEY_Down, RETROK_DOWN },
+ { KEY_Right, RETROK_RIGHT },
+ { KEY_Left, RETROK_LEFT },
+ { KEY_Insert, RETROK_INSERT },
+ { KEY_Home, RETROK_HOME },
+ { KEY_End, RETROK_END },
+ { KEY_PageUp, RETROK_PAGEUP },
+ { KEY_PageDown, RETROK_PAGEDOWN },
+
+ { KEY_F1, RETROK_F1 },
+ { KEY_F2, RETROK_F2 },
+ { KEY_F3, RETROK_F3 },
+ { KEY_F4, RETROK_F4 },
+ { KEY_F5, RETROK_F5 },
+ { KEY_F6, RETROK_F6 },
+ { KEY_F7, RETROK_F7 },
+ { KEY_F8, RETROK_F8 },
+ { KEY_F9, RETROK_F9 },
+ { KEY_F10, RETROK_F10 },
+ { KEY_F11, RETROK_F11 },
+ { KEY_F12, RETROK_F12 },
+ { KEY_F13, RETROK_F13 },
+ { KEY_F14, RETROK_F14 },
+ { KEY_F15, RETROK_F15 },
+
+// RETROK_NUMLOCK },
+ { KEY_CapsLock, RETROK_CAPSLOCK },
+// RETROK_SCROLLOCK },
+ { KEY_RightShift, RETROK_RSHIFT },
+ { KEY_LeftShift, RETROK_LSHIFT },
+ { KEY_RightControl, RETROK_RCTRL },
+ { KEY_LeftControl, RETROK_LCTRL },
+ { KEY_RightAlt, RETROK_RALT },
+ { KEY_LeftAlt, RETROK_LALT },
+ { KEY_RightGUI, RETROK_RMETA },
+ { KEY_LeftGUI, RETROK_RMETA },
+// RETROK_LSUPER },
+// RETROK_RSUPER },
+// RETROK_MODE },
+// RETROK_COMPOSE },
+
+// RETROK_HELP },
+ { KEY_PrintScreen, RETROK_PRINT },
+// RETROK_SYSREQ },
+// RETROK_BREAK },
+ { KEY_Menu, RETROK_MENU },
+// RETROK_POWER },
+// RETROK_EURO },
+// RETROK_UNDO },
+ { 0, RETROK_UNKNOWN }
+};
+
+
+const char* apple_keycode_hidusage_to_name(uint32_t hid_usage)
+{
+ for (int i = 0; apple_key_name_map[i].hid_id; i ++)
+ if (apple_key_name_map[i].hid_id == hid_usage)
+ return apple_key_name_map[i].keyname;
+
+ return "nul";
+}
diff --git a/apple/common/main.m b/apple/common/main.m
new file mode 100644
index 0000000000..211f6f7f30
--- /dev/null
+++ b/apple/common/main.m
@@ -0,0 +1,184 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2013 - Jason Fetters
+ *
+ * RetroArch is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with RetroArch.
+ * If not, see .
+ */
+
+#include
+#include
+
+#import "RetroArch_Apple.h"
+#include "rarch_wrapper.h"
+
+#include "apple_input.h"
+
+#include "file.h"
+
+char** apple_argv;
+
+id apple_platform;
+
+void apple_event_basic_command(void* userdata)
+{
+ switch ((enum basic_event_t)userdata)
+ {
+ case RESET: rarch_game_reset(); return;
+ case LOAD_STATE: rarch_load_state(); return;
+ case SAVE_STATE: rarch_save_state(); return;
+ case QUIT: g_extern.system.shutdown = true; return;
+ }
+}
+
+void apple_event_set_state_slot(void* userdata)
+{
+ g_extern.state_slot = (uint32_t)userdata;
+}
+
+void apple_event_show_rgui(void* userdata)
+{
+ const bool in_menu = g_extern.lifecycle_mode_state & (1 << MODE_MENU);
+ g_extern.lifecycle_mode_state &= ~(1ULL << (in_menu ? MODE_MENU : MODE_GAME));
+ g_extern.lifecycle_mode_state |= (1ULL << (in_menu ? MODE_GAME : MODE_MENU));
+}
+
+static void event_reload_config(void* userdata)
+{
+ objc_clear_config_hack();
+
+ uninit_drivers();
+ config_load();
+ init_drivers();
+}
+
+void apple_refresh_config()
+{
+ if (apple_is_running)
+ apple_frontend_post_event(&event_reload_config, 0);
+ else
+ objc_clear_config_hack();
+}
+
+pthread_mutex_t stasis_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void event_stasis(void* userdata)
+{
+ uninit_drivers();
+ pthread_mutex_lock(&stasis_mutex);
+ pthread_mutex_unlock(&stasis_mutex);
+ init_drivers();
+}
+
+void apple_enter_stasis()
+{
+ if (apple_is_running)
+ {
+ pthread_mutex_lock(&stasis_mutex);
+ apple_frontend_post_event(event_stasis, 0);
+ }
+}
+
+void apple_exit_stasis(bool reload_config)
+{
+ if (reload_config)
+ {
+ objc_clear_config_hack();
+ config_load();
+ }
+
+ if (apple_is_running)
+ pthread_mutex_unlock(&stasis_mutex);
+}
+
+#pragma mark EMULATION
+static pthread_t apple_retro_thread;
+bool apple_is_paused;
+bool apple_is_running;
+bool apple_use_tv_mode;
+RAModuleInfo* apple_core;
+
+void* rarch_main_spring(void* args)
+{
+ char** argv = args;
+
+ uint32_t argc = 0;
+ while (argv && argv[argc]) argc++;
+
+ if (rarch_main(argc, argv))
+ {
+ rarch_main_clear_state();
+ dispatch_async_f(dispatch_get_main_queue(), (void*)1, apple_rarch_exited);
+ }
+
+ return 0;
+}
+
+void apple_run_core(RAModuleInfo* core, const char* file)
+{
+ if (!apple_is_running)
+ {
+ [apple_platform loadingCore:core withFile:file];
+
+ apple_core = core;
+ apple_is_running = true;
+
+ static char config_path[PATH_MAX];
+ static char core_path[PATH_MAX];
+ static char file_path[PATH_MAX];
+
+ if (!apple_argv)
+ {
+ NSString* config_to_use = apple_core ? apple_core.configFile : apple_platform.globalConfigFile;
+ strlcpy(config_path, config_to_use.UTF8String, sizeof(config_path));
+
+ static const char* const argv_game[] = { "retroarch", "-c", config_path, "-L", core_path, file_path, 0 };
+ static const char* const argv_menu[] = { "retroarch", "-c", config_path, "--menu", 0 };
+
+ if (file && core)
+ {
+ strlcpy(core_path, apple_core.path.UTF8String, sizeof(core_path));
+ strlcpy(file_path, file, sizeof(file_path));
+ }
+
+ apple_argv = (char**)((file && core) ? argv_game : argv_menu);
+ }
+
+ if (pthread_create(&apple_retro_thread, 0, rarch_main_spring, apple_argv))
+ {
+ apple_argv = 0;
+
+ apple_rarch_exited((void*)1);
+ return;
+ }
+
+ apple_argv = 0;
+
+ pthread_detach(apple_retro_thread);
+ }
+}
+
+void apple_rarch_exited(void* result)
+{
+ if (result)
+ apple_display_alert(@"Failed to load game.", 0);
+
+ RAModuleInfo* used_core = apple_core;
+ apple_core = nil;
+
+ if (apple_is_running)
+ {
+ apple_is_running = false;
+ [apple_platform unloadingCore:used_core];
+ }
+
+ if (apple_use_tv_mode)
+ apple_run_core(nil, 0);
+}
diff --git a/apple/RetroArch/rarch_wrapper.h b/apple/common/rarch_wrapper.h
similarity index 64%
rename from apple/RetroArch/rarch_wrapper.h
rename to apple/common/rarch_wrapper.h
index b92cf5eb83..4217f79fff 100644
--- a/apple/RetroArch/rarch_wrapper.h
+++ b/apple/common/rarch_wrapper.h
@@ -17,19 +17,25 @@
#ifndef __APPLE_RARCH_WRAPPER_H__
#define __APPLE_RARCH_WRAPPER_H__
+#include "gfx/gfx_context.h"
+
// The result needs to be free()'d
char* ios_get_rarch_system_directory();
// These functions should only be called as arguments to dispatch_sync
void apple_rarch_exited (void* result);
-// These functions must only be called in gfx/context/ioseagl_ctx.c
-bool apple_init_game_view(void);
-void apple_destroy_game_view(void);
-void apple_flip_game_view(void);
-void apple_set_game_view_sync(unsigned interval);
-void apple_get_game_view_size(unsigned *width, unsigned *height);
-void *apple_get_proc_address(const char *symbol_name);
+// These functions must only be called in gfx/context/apple_gl_context.c
+bool apple_gfx_ctx_init();
+void apple_gfx_ctx_destroy();
+bool apple_gfx_ctx_bind_api(enum gfx_ctx_api api, unsigned major, unsigned minor);
+void apple_gfx_ctx_swap_interval(unsigned interval);
+bool apple_gfx_ctx_set_video_mode(unsigned width, unsigned height, bool fullscreen);
+void apple_gfx_ctx_get_video_size(unsigned* width, unsigned* height);
+void apple_gfx_ctx_update_window_title(void);
+bool apple_gfx_ctx_has_focus(void);
+void apple_gfx_ctx_swap_buffers();
+gfx_ctx_proc_t apple_gfx_ctx_get_proc_address(const char *symbol_name);
#ifdef IOS
void apple_bind_game_view_fbo(void);
diff --git a/apple/RetroArch/setting_data.h b/apple/common/setting_data.h
similarity index 60%
rename from apple/RetroArch/setting_data.h
rename to apple/common/setting_data.h
index e7f8246dc5..dc5fa2c39e 100644
--- a/apple/RetroArch/setting_data.h
+++ b/apple/common/setting_data.h
@@ -18,8 +18,8 @@
#include "general.h"
-enum setting_type { ST_NONE, ST_BOOL, ST_INT, ST_FLOAT, ST_PATH, ST_STRING, ST_HEX, ST_GROUP, ST_SUB_GROUP,
- ST_END_GROUP, ST_END_SUB_GROUP };
+enum setting_type { ST_NONE, ST_BOOL, ST_INT, ST_FLOAT, ST_PATH, ST_STRING, ST_HEX, ST_BIND,
+ ST_GROUP, ST_SUB_GROUP, ST_END_GROUP, ST_END_SUB_GROUP };
typedef struct
{
@@ -28,36 +28,43 @@ typedef struct
const char* name;
void* value;
+ uint32_t size;
const char* short_description;
- const char* long_description;
-
- const char** values;
uint32_t input_player;
+
double min;
double max;
bool allow_blank;
} rarch_setting_t;
-#define START_GROUP(NAME) { ST_GROUP, NAME, 0, 0, 0, 0, 0, 0.0, 0.0, false },
-#define END_GROUP() { ST_END_GROUP, 0, 0, 0, 0, 0, 0, 0.0, 0.0, false },
-#define START_SUB_GROUP(NAME) { ST_SUB_GROUP, NAME, 0, 0, 0, 0, 0, 0.0, 0.0, false },
-#define END_SUB_GROUP() { ST_END_SUB_GROUP, 0, 0, 0, 0, 0, 0, 0.0, 0.0, false },
-#define START_GROUP(NAME) { ST_GROUP, NAME, 0, 0, 0, 0, 0, 0.0, 0.0, false },
-#define END_GROUP() { ST_END_GROUP, 0, 0, 0, 0, 0, 0, 0.0, 0.0, false },
-#define CONFIG_BOOL(TARGET, NAME, SHORT) { ST_BOOL, NAME, &TARGET, SHORT, 0, 0, 0, 0.0, 0.0, false },
-#define CONFIG_INT(TARGET, NAME, SHORT) { ST_INT, NAME, &TARGET, SHORT, 0, 0, 0, 0.0, 0.0, false },
-#define CONFIG_FLOAT(TARGET, NAME, SHORT) { ST_FLOAT, NAME, &TARGET, SHORT, 0, 0, 0, 0.0, 0.0, false },
-#define CONFIG_PATH(TARGET, NAME, SHORT) { ST_PATH, NAME, &TARGET, SHORT, 0, 0, 0, 0.0, 0.0, false },
-#define CONFIG_STRING(TARGET, NAME, SHORT) { ST_STRING, NAME, &TARGET, SHORT, 0, 0, 0, 0.0, 0.0, false },
-#define CONFIG_HEX(TARGET, NAME, SHORT) { ST_HEX, NAME, &TARGET, SHORT, 0, 0, 0, 0.0, 0.0, false },
+extern struct settings fake_settings;
+extern struct global fake_extern;
+
+// HACK
+#define g_settings fake_settings
+#define g_extern fake_extern
+
+#define START_GROUP(NAME) { ST_GROUP, NAME },
+#define END_GROUP() { ST_END_GROUP },
+#define START_SUB_GROUP(NAME) { ST_SUB_GROUP, NAME },
+#define END_SUB_GROUP() { ST_END_SUB_GROUP },
+#define CONFIG_BOOL(TARGET, NAME, SHORT) { ST_BOOL, NAME, &TARGET, sizeof(TARGET), SHORT },
+#define CONFIG_INT(TARGET, NAME, SHORT) { ST_INT, NAME, &TARGET, sizeof(TARGET), SHORT },
+#define CONFIG_FLOAT(TARGET, NAME, SHORT) { ST_FLOAT, NAME, &TARGET, sizeof(TARGET), SHORT },
+#define CONFIG_PATH(TARGET, NAME, SHORT) { ST_PATH, NAME, &TARGET, sizeof(TARGET), SHORT },
+#define CONFIG_STRING(TARGET, NAME, SHORT) { ST_STRING, NAME, &TARGET, sizeof(TARGET), SHORT },
+#define CONFIG_HEX(TARGET, NAME, SHORT) { ST_HEX, NAME, &TARGET, sizeof(TARGET), SHORT },
+
+#define CONFIG_BIND(TARGET, PLAYER, NAME, SHORT) { ST_BIND, NAME, &TARGET, sizeof(TARGET), SHORT, PLAYER },
const rarch_setting_t setting_data[] =
{
/***********/
/* DRIVERS */
/***********/
+#if 0
START_GROUP("Drivers")
START_SUB_GROUP("Drivers")
CONFIG_STRING(g_settings.video.driver, "video_driver", "Video Driver")
@@ -67,6 +74,7 @@ const rarch_setting_t setting_data[] =
CONFIG_STRING(g_settings.input.joypad_driver, "input_joypad_driver", "Joypad Driver")
END_SUB_GROUP()
END_GROUP()
+#endif
/*********/
/* PATHS */
@@ -92,7 +100,6 @@ const rarch_setting_t setting_data[] =
END_GROUP()
-
/*************/
/* EMULATION */
/*************/
@@ -113,6 +120,82 @@ const rarch_setting_t setting_data[] =
END_SUB_GROUP()
END_GROUP()
+ /*********/
+ /* VIDEO */
+ /*********/
+ START_GROUP("Video")
+ START_SUB_GROUP("Monitor")
+ CONFIG_INT(g_settings.video.monitor_index, "video_monitor_index", "Monitor Index")
+ CONFIG_BOOL(g_settings.video.fullscreen, "video_fullscreen", "Use Fullscreen mode") // if (!g_extern.force_fullscreen)
+ CONFIG_BOOL(g_settings.video.windowed_fullscreen, "video_windowed_fullscreen", "Windowed Fullscreen Mode")
+ CONFIG_INT(g_settings.video.fullscreen_x, "video_fullscreen_x", "Fullscreen Width")
+ CONFIG_INT(g_settings.video.fullscreen_y, "video_fullscreen_y", "Fullscreen Height")
+ CONFIG_FLOAT(g_settings.video.refresh_rate, "video_refresh_rate", "Refresh Rate")
+ END_SUB_GROUP()
+
+#if 0
+ /* Video: Window Manager */
+ START_SUB_GROUP("Window Manager")
+ CONFIG_BOOL(g_settings.video.disable_composition, "video_disable_composition", "Disable WM Composition")
+ END_SUB_GROUP()
+#endif
+
+ START_SUB_GROUP("Aspect")
+ CONFIG_BOOL(g_settings.video.force_aspect, "video_force_aspect", "Force aspect ratio")
+ CONFIG_FLOAT(g_settings.video.aspect_ratio, "video_aspect_ratio", "Aspect Ratio")
+ CONFIG_BOOL(g_settings.video.aspect_ratio_auto, "video_aspect_ratio_auto", "Use Auto Aspect Ratio")
+ CONFIG_INT(g_settings.video.aspect_ratio_idx, "aspect_ratio_index", "Aspect Ratio Index")
+ END_SUB_GROUP()
+
+ START_SUB_GROUP("Scaling")
+ CONFIG_FLOAT(g_settings.video.xscale, "video_xscale", "X Scale")
+ CONFIG_FLOAT(g_settings.video.yscale, "video_yscale", "Y Scale")
+ CONFIG_BOOL(g_settings.video.scale_integer, "video_scale_integer", "Force integer scaling")
+
+ CONFIG_INT(g_extern.console.screen.viewports.custom_vp.x, "custom_viewport_x", "Custom Viewport X")
+ CONFIG_INT(g_extern.console.screen.viewports.custom_vp.y, "custom_viewport_y", "Custom Viewport Y")
+ CONFIG_INT(g_extern.console.screen.viewports.custom_vp.width, "custom_viewport_width", "Custom Viewport Width")
+ CONFIG_INT(g_extern.console.screen.viewports.custom_vp.height, "custom_viewport_height", "Custom Viewport Height")
+
+ CONFIG_BOOL(g_settings.video.smooth, "video_smooth", "Use bilinear filtering")
+ END_SUB_GROUP()
+
+ START_SUB_GROUP("Shader")
+ CONFIG_BOOL(g_settings.video.shader_enable, "video_shader_enable", "Enable Shaders")
+ CONFIG_PATH(g_settings.video.shader_dir, "video_shader_dir", "Shader Directory")
+ CONFIG_PATH(g_settings.video.shader_path, "video_shader", "Shader")
+ END_SUB_GROUP()
+
+ START_SUB_GROUP("Sync")
+ CONFIG_BOOL(g_settings.video.threaded, "video_threaded", "Use threaded video")
+ CONFIG_BOOL(g_settings.video.vsync, "video_vsync", "Use VSync")
+ CONFIG_BOOL(g_settings.video.hard_sync, "video_hard_sync", "Use OpenGL Hard Sync")
+ CONFIG_INT(g_settings.video.hard_sync_frames, "video_hard_sync_frames", "Number of Hard Sync frames") // 0 - 3
+ END_SUB_GROUP()
+
+ START_SUB_GROUP("Misc")
+ CONFIG_BOOL(g_settings.video.post_filter_record, "video_post_filter_record", "Post filter record")
+ CONFIG_BOOL(g_settings.video.gpu_record, "video_gpu_record", "GPU Record")
+ CONFIG_BOOL(g_settings.video.gpu_screenshot, "video_gpu_screenshot", "GPU Screenshot")
+ CONFIG_BOOL(g_settings.video.allow_rotate, "video_allow_rotate", "Allow rotation")
+ CONFIG_BOOL(g_settings.video.crop_overscan, "video_crop_overscan", "Crop Overscan")
+
+ #ifdef HAVE_DYLIB
+ CONFIG_PATH(g_settings.video.filter_path, "video_filter", "Software filter"),
+ #endif
+ END_SUB_GROUP()
+
+ START_SUB_GROUP("Messages")
+ CONFIG_PATH(g_settings.video.font_path, "video_font_path", "Font Path")
+ CONFIG_FLOAT(g_settings.video.font_size, "video_font_size", "Font Size")
+ CONFIG_BOOL(g_settings.video.font_enable, "video_font_enable", "Font Enable")
+ CONFIG_BOOL(g_settings.video.font_scale, "video_font_scale", "Font Scale")
+ CONFIG_FLOAT(g_settings.video.msg_pos_x, "video_message_pos_x", "Message X Position")
+ CONFIG_FLOAT(g_settings.video.msg_pos_y, "video_message_pos_y", "Message Y Position")
+ /* message color */
+ END_SUB_GROUP()
+ END_GROUP()
+
/*********/
/* AUDIO */
/*********/
@@ -162,8 +245,8 @@ const rarch_setting_t setting_data[] =
/* Input: Overlay */
#ifdef HAVE_OVERLAY
CONFIG_PATH(g_settings.input.overlay, "input_overlay", "Input Overlay")
- CONFIG_FLOAT(g_settings.input.overlay_opacity, "overlay_opacity", "Overlay Opacity")
- CONFIG_FLOAT(g_settings.input.overlay_scale, "overlay_scale", "Overlay Scale")
+ CONFIG_FLOAT(g_settings.input.overlay_opacity, "input_overlay_opacity", "Overlay Opacity")
+ CONFIG_FLOAT(g_settings.input.overlay_scale, "input_overlay_scale", "Overlay Scale")
#endif
/* Input: Android */
@@ -175,79 +258,67 @@ const rarch_setting_t setting_data[] =
CONFIG_INT(g_settings.input.icade_profile[3], "input_autodetect_icade_profile_pad4", "iCade 4")
#endif
END_SUB_GROUP()
- END_GROUP()
- /*********/
- /* VIDEO */
- /*********/
- START_GROUP("Video")
- START_SUB_GROUP("Monitor")
- CONFIG_INT(g_settings.video.monitor_index, "video_monitor_index", "Monitor Index")
- CONFIG_BOOL(g_settings.video.fullscreen, "video_fullscreen", "Use Fullscreen mode") // if (!g_extern.force_fullscreen)
- CONFIG_BOOL(g_settings.video.windowed_fullscreen, "video_windowed_fullscreen", "Windowed Fullscreen Mode")
- CONFIG_INT(g_settings.video.fullscreen_x, "video_fullscreen_x", "Fullscreen Width")
- CONFIG_INT(g_settings.video.fullscreen_y, "video_fullscreen_y", "Fullscreen Height")
- CONFIG_FLOAT(g_settings.video.refresh_rate, "video_refresh_rate", "Refresh Rate")
- END_SUB_GROUP()
-
- /* Video: Window Manager */
- START_SUB_GROUP("Window Manager")
- CONFIG_BOOL(g_settings.video.disable_composition, "video_disable_composition", "Disable WM Composition")
+ START_SUB_GROUP("Meta Keys")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_FAST_FORWARD_KEY], 0, "toggle_fast_forward", "Fast forward toggle")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_FAST_FORWARD_HOLD_KEY], 0, "hold_fast_forward", "Fast forward hold")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_LOAD_STATE_KEY], 0, "load_state", "Load state")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_SAVE_STATE_KEY], 0, "save_state", "Save state")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_FULLSCREEN_TOGGLE_KEY], 0, "toggle_fullscreen", "Fullscreen toggle")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_QUIT_KEY], 0, "exit_emulator", "Quit RetroArch")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_STATE_SLOT_PLUS], 0, "state_slot_increase", "Savestate slot +")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_STATE_SLOT_MINUS], 0, "state_slot_decrease", "Savestate slot -")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_REWIND], 0, "rewind", "Rewind")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_MOVIE_RECORD_TOGGLE], 0, "movie_record_toggle", "Movie record toggle")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_PAUSE_TOGGLE], 0, "pause_toggle", "Pause toggle")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_FRAMEADVANCE], 0, "frame_advance", "Frameadvance")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_RESET], 0, "reset", "Reset game")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_SHADER_NEXT], 0, "shader_next", "Next shader")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_SHADER_PREV], 0, "shader_prev", "Previous shader")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_CHEAT_INDEX_PLUS], 0, "cheat_index_plus", "Cheat index +")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_CHEAT_INDEX_MINUS], 0, "cheat_index_minus", "Cheat index -")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_CHEAT_TOGGLE], 0, "cheat_toggle", "Cheat toggle")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_SCREENSHOT], 0, "screenshot", "Take screenshot")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_DSP_CONFIG], 0, "dsp_config", "DSP config")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_MUTE], 0, "audio_mute", "Audio mute toggle")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_NETPLAY_FLIP], 0, "netplay_flip_players", "Netplay flip players")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_SLOWMOTION], 0, "slowmotion", "Slow motion")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_ENABLE_HOTKEY], 0, "enable_hotkey", "Enable hotkeys")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_VOLUME_UP], 0, "volume_up", "Volume +")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_VOLUME_DOWN], 0, "volume_down", "Volume -")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_OVERLAY_NEXT], 0, "overlay_next", "Overlay next")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_DISK_EJECT_TOGGLE], 0, "disk_eject_toggle", "Disk eject toggle")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_DISK_NEXT], 0, "disk_next", "Disk next")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_GRAB_MOUSE_TOGGLE], 0, "grab_mouse_toggle", "Grab mouse toggle")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_MENU_TOGGLE], 0, "menu_toggle", "RGUI menu toggle")
END_SUB_GROUP()
- START_SUB_GROUP("Aspect")
- CONFIG_BOOL(g_settings.video.force_aspect, "video_force_aspect", "Force aspect ratio")
- CONFIG_FLOAT(g_settings.video.aspect_ratio, "video_aspect_ratio", "Aspect Ratio")
- CONFIG_INT(g_settings.video.aspect_ratio_idx, "aspect_ratio_index", "Aspect Ratio Index")
- CONFIG_BOOL(g_settings.video.aspect_ratio_auto, "video_aspect_ratio_auto", "Use Auto Aspect Ratio")
- END_SUB_GROUP()
-
- START_SUB_GROUP("Scaling")
- CONFIG_FLOAT(g_settings.video.xscale, "video_xscale", "X Scale")
- CONFIG_FLOAT(g_settings.video.yscale, "video_yscale", "Y Scale")
- CONFIG_BOOL(g_settings.video.scale_integer, "video_scale_integer", "Force integer scaling")
-
- CONFIG_INT(g_extern.console.screen.viewports.custom_vp.x, "custom_viewport_x", "Custom Viewport X")
- CONFIG_INT(g_extern.console.screen.viewports.custom_vp.y, "custom_viewport_y", "Custom Viewport Y")
- CONFIG_INT(g_extern.console.screen.viewports.custom_vp.width, "custom_viewport_width", "Custom Viewport Width")
- CONFIG_INT(g_extern.console.screen.viewports.custom_vp.height, "custom_viewport_height", "Custom Viewport Height")
-
- CONFIG_BOOL(g_settings.video.smooth, "video_smooth", "Use bilinear filtering")
- END_SUB_GROUP()
-
- START_SUB_GROUP("Shader")
- CONFIG_BOOL(g_settings.video.shader_enable, "video_shader_enable", "Enable Shaders")
- CONFIG_PATH(g_settings.video.shader_dir, "video_shader_dir", "Shader Directory")
- CONFIG_PATH(g_settings.video.shader_path, "video_shader", "Shader")
- END_SUB_GROUP()
-
- START_SUB_GROUP("Sync")
- CONFIG_BOOL(g_settings.video.threaded, "video_threaded", "Use threaded video")
- CONFIG_BOOL(g_settings.video.vsync, "video_vsync", "Use VSync")
- CONFIG_BOOL(g_settings.video.hard_sync, "video_hard_sync", "Use OpenGL Hard Sync")
- CONFIG_INT(g_settings.video.hard_sync_frames, "video_hard_sync_frames", "Number of Hard Sync frames") // 0 - 3
- END_SUB_GROUP()
-
- START_SUB_GROUP("Misc")
- CONFIG_BOOL(g_settings.video.post_filter_record, "video_post_filter_record", "Post filter record")
- CONFIG_BOOL(g_settings.video.gpu_record, "video_gpu_record", "GPU Record")
- CONFIG_BOOL(g_settings.video.gpu_screenshot, "video_gpu_screenshot", "GPU Screenshot")
- CONFIG_BOOL(g_settings.video.allow_rotate, "video_allow_rotate", "Allow rotation")
- CONFIG_BOOL(g_settings.video.crop_overscan, "video_crop_overscan", "Crop Overscan")
-
- #ifdef HAVE_DYLIB
- CONFIG_PATH(g_settings.video.filter_path, "video_filter", "Software filter"),
- #endif
- END_SUB_GROUP()
-
- START_SUB_GROUP("Messages")
- CONFIG_PATH(g_settings.video.font_path, "video_font_path", "Font Path")
- CONFIG_FLOAT(g_settings.video.font_size, "video_font_size", "Font Size")
- CONFIG_BOOL(g_settings.video.font_enable, "video_font_enable", "Font Enable")
- CONFIG_BOOL(g_settings.video.font_scale, "video_font_scale", "Font Scale")
- CONFIG_FLOAT(g_settings.video.msg_pos_x, "video_message_pos_x", "Message X Position")
- CONFIG_FLOAT(g_settings.video.msg_pos_y, "video_message_pos_y", "Message Y Position")
- /* message color */
+ START_SUB_GROUP("Player 1")
+ CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_UP], 1, "up", "Up D-pad")
+ CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_DOWN], 1, "down", "Down D-pad")
+ CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_LEFT], 1, "left", "Left D-pad")
+ CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_RIGHT], 1, "right", "Right D-pad")
+ CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_SELECT],1, "select", "Select button")
+ CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_START], 1, "start", "Start button")
+ CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_B], 1, "b", "B button (down)")
+ CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_A], 1, "a", "A button (right)")
+ CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_X], 1, "x", "X button (top)")
+ CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_Y], 1, "y", "Y button (left)")
+ CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_L], 1, "l", "L button (left shoulder)")
+ CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_R], 1, "r", "R button (right shoulder)")
+ CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_L2], 1, "l2", "L2 button (left shoulder #2)")
+ CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_R2], 1, "r2", "R2 button (right shoulder #2)")
+ CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_L3], 1, "l3", "L3 button (left analog button)")
+ CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_R3], 1, "r3", "R3 button (right analog button)")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_ANALOG_LEFT_Y_MINUS], 1, "l_y_minus", "Left analog Y- (up)")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_ANALOG_LEFT_Y_PLUS], 1, "l_y_plus", "Left analog Y+ (down)")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_ANALOG_LEFT_X_MINUS], 1, "l_x_minus", "Left analog X- (left)")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_ANALOG_LEFT_X_PLUS], 1, "l_x_plus", "Left analog X+ (right)")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_ANALOG_RIGHT_Y_MINUS], 1, "r_y_minus", "Right analog Y- (up)")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_ANALOG_RIGHT_Y_PLUS], 1, "r_y_plus", "Right analog Y+ (down)")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_ANALOG_RIGHT_X_MINUS], 1, "r_x_minus", "Right analog X- (left)")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_ANALOG_RIGHT_X_PLUS], 1, "r_x_plus", "Right analog X+ (right)")
+ CONFIG_BIND(g_settings.input.binds[0][RARCH_TURBO_ENABLE], 1, "turbo", "Turbo enable")
END_SUB_GROUP()
END_GROUP()
@@ -266,4 +337,11 @@ const rarch_setting_t setting_data[] =
{ 0 }
};
+// HACK
+#undef g_settings
+#undef g_extern
+
+// Keyboard
+#include "keycode.h"
+
#endif
\ No newline at end of file
diff --git a/apple/RetroArch/utility.m b/apple/common/utility.m
similarity index 96%
rename from apple/RetroArch/utility.m
rename to apple/common/utility.m
index 0836e9fdec..1c8ffb8608 100644
--- a/apple/RetroArch/utility.m
+++ b/apple/common/utility.m
@@ -57,7 +57,7 @@ NSString* objc_get_value_from_config(config_file_t* config, NSString* name, NSSt
if (config)
config_get_string(config, [name UTF8String], &data);
- NSString* result = data ? [NSString stringWithUTF8String:data] : defaultValue;
+ NSString* result = data ? @(data) : defaultValue;
free(data);
return result;
}
@@ -110,6 +110,11 @@ char* ios_get_rarch_system_directory()
return self.sections[indexPath.section][indexPath.row + 1];
}
+- (void)reset
+{
+ self.sections = [NSMutableArray array];
+ [self.tableView reloadData];
+}
@end
#endif
diff --git a/apple/iOS/RALogView.m b/apple/iOS/RALogView.m
index d384515334..af802dceca 100644
--- a/apple/iOS/RALogView.m
+++ b/apple/iOS/RALogView.m
@@ -34,7 +34,7 @@ void ios_add_log_message(const char* format, ...)
va_start(args, format);
vsnprintf(buffer, 512, format, args);
va_end(args);
- [g_messages addObject:[NSString stringWithUTF8String: buffer]];
+ [g_messages addObject:@(buffer)];
pthread_mutex_unlock(&g_lock);
}
diff --git a/apple/iOS/input/BTStack/btdynamic.c b/apple/iOS/bluetooth/btdynamic.c
similarity index 98%
rename from apple/iOS/input/BTStack/btdynamic.c
rename to apple/iOS/bluetooth/btdynamic.c
index 9dfa1a95b6..bfdcde2857 100644
--- a/apple/iOS/input/BTStack/btdynamic.c
+++ b/apple/iOS/bluetooth/btdynamic.c
@@ -17,7 +17,7 @@
#include
#include
-#include "../../../RetroArch/rarch_wrapper.h"
+#include "apple/common/rarch_wrapper.h"
#define BUILDING_BTDYNAMIC
#include "btdynamic.h"
diff --git a/apple/iOS/input/BTStack/btdynamic.h b/apple/iOS/bluetooth/btdynamic.h
similarity index 100%
rename from apple/iOS/input/BTStack/btdynamic.h
rename to apple/iOS/bluetooth/btdynamic.h
diff --git a/apple/iOS/input/BTStack/btpad.c b/apple/iOS/bluetooth/btpad.c
similarity index 71%
rename from apple/iOS/input/BTStack/btpad.c
rename to apple/iOS/bluetooth/btpad.c
index babb0ba3fc..abb6333ded 100644
--- a/apple/iOS/input/BTStack/btpad.c
+++ b/apple/iOS/bluetooth/btpad.c
@@ -20,15 +20,39 @@
#include
#include
-#include "../../../RetroArch/rarch_wrapper.h"
+#include "apple/common/rarch_wrapper.h"
+#include "apple/common/hidpad/hidpad.h"
#include "btdynamic.h"
#include "btpad.h"
#include "btpad_queue.h"
-#include "wiimote.h"
-static btpad_connection_t btpad_connection[MAX_PADS];
-static struct btpad_interface* btpad_iface[MAX_PADS];
-static void* btpad_device[MAX_PADS];
+// Private interface
+enum btpad_state { BTPAD_EMPTY, BTPAD_CONNECTING, BTPAD_CONNECTED };
+
+struct hidpad_connection
+{
+ uint32_t slot;
+
+ struct hidpad_interface* interface;
+ void* hidpad;
+
+ enum btpad_state state;
+
+ bool has_address;
+ bd_addr_t address;
+
+ uint16_t handle;
+ uint16_t channels[2]; //0: Control, 1: Interrupt
+};
+
+static struct hidpad_connection g_connected_pads[MAX_PADS];
+
+void hidpad_send_control(struct hidpad_connection* connection, uint8_t* data, size_t size)
+{
+ bt_send_l2cap_ptr(connection->channels[0], data, size);
+}
+
+
static bool inquiry_off;
static bool inquiry_running;
@@ -41,35 +65,18 @@ void btpad_set_inquiry_state(bool on)
btpad_queue_hci_inquiry(HCI_INQUIRY_LAP, 3, 1);
}
-// MAIN THREAD ONLY
-uint32_t btpad_get_buttons(uint32_t slot)
-{
- if (slot < MAX_PADS && btpad_device[slot] && btpad_iface[slot])
- return btpad_iface[slot]->get_buttons(btpad_device[slot]);
-
- return 0;
-}
-
-int16_t btpad_get_axis(uint32_t slot, unsigned axis)
-{
- if (slot < MAX_PADS && btpad_device[slot] && btpad_iface[slot])
- return btpad_iface[slot]->get_axis(btpad_device[slot], axis);
-
- return 0;
-}
-
// Internal interface:
static int32_t btpad_find_slot_for(uint16_t handle, bd_addr_t address)
{
for (int i = 0; i < MAX_PADS; i ++)
{
- if (!btpad_connection[i].handle && !btpad_connection[i].has_address)
+ if (!g_connected_pads[i].handle && !g_connected_pads[i].has_address)
continue;
- if (handle && btpad_connection[i].handle && handle != btpad_connection[i].handle)
+ if (handle && g_connected_pads[i].handle && handle != g_connected_pads[i].handle)
continue;
- if (address && btpad_connection[i].has_address && (BD_ADDR_CMP(address, btpad_connection[i].address)))
+ if (address && g_connected_pads[i].has_address && (BD_ADDR_CMP(address, g_connected_pads[i].address)))
continue;
return i;
@@ -81,7 +88,7 @@ static int32_t btpad_find_slot_for(uint16_t handle, bd_addr_t address)
static int32_t btpad_find_slot_with_state(enum btpad_state state)
{
for (int i = 0; i < MAX_PADS; i ++)
- if (btpad_connection[i].state == state)
+ if (g_connected_pads[i].state == state)
return i;
return -1;
@@ -92,19 +99,16 @@ static void btpad_disconnect_pad(uint32_t slot)
if (slot > MAX_PADS)
return;
- if (btpad_iface[slot] && btpad_device[slot])
+ if (g_connected_pads[slot].interface && g_connected_pads[slot].hidpad)
{
ios_add_log_message("BTpad: Disconnecting slot %d", slot);
-
- btpad_iface[slot]->disconnect(btpad_device[slot]);
- btpad_device[slot] = 0;
- btpad_iface[slot] = 0;
+ g_connected_pads[slot].interface->disconnect(g_connected_pads[slot].hidpad);
}
- if (btpad_connection[slot].handle)
- btpad_queue_hci_disconnect(btpad_connection[slot].handle, 0x15);
+ if (g_connected_pads[slot].handle)
+ btpad_queue_hci_disconnect(g_connected_pads[slot].handle, 0x15);
- memset(&btpad_connection[slot], 0, sizeof(btpad_connection_t));
+ memset(&g_connected_pads[slot], 0, sizeof(struct hidpad_connection));
}
static void btpad_disconnect_all_pads()
@@ -134,7 +138,7 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
btpad_queue_run(1);
}
- else if(packet[2] > HCI_STATE_WORKING && btpad_iface && btpad_device)
+ else if(packet[2] > HCI_STATE_WORKING)
{
btpad_disconnect_all_pads();
}
@@ -171,14 +175,14 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
{
ios_add_log_message("BTpad: Inquiry found device (Slot %d)", slot);
- memcpy(btpad_connection[slot].address, event_addr, sizeof(bd_addr_t));
+ memcpy(g_connected_pads[slot].address, event_addr, sizeof(bd_addr_t));
- btpad_connection[slot].has_address = true;
- btpad_connection[slot].state = BTPAD_CONNECTING;
- btpad_connection[slot].slot = slot;
+ g_connected_pads[slot].has_address = true;
+ g_connected_pads[slot].state = BTPAD_CONNECTING;
+ g_connected_pads[slot].slot = slot;
- bt_send_cmd_ptr(l2cap_create_channel_ptr, btpad_connection[slot].address, PSM_HID_CONTROL);
- bt_send_cmd_ptr(l2cap_create_channel_ptr, btpad_connection[slot].address, PSM_HID_INTERRUPT);
+ bt_send_cmd_ptr(l2cap_create_channel_ptr, g_connected_pads[slot].address, PSM_HID_CONTROL);
+ bt_send_cmd_ptr(l2cap_create_channel_ptr, g_connected_pads[slot].address, PSM_HID_INTERRUPT);
}
}
}
@@ -213,19 +217,19 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
}
ios_add_log_message("BTpad: L2CAP channel opened: (Slot: %d, PSM: %02X)", slot, psm);
- btpad_connection[slot].handle = handle;
+ g_connected_pads[slot].handle = handle;
if (psm == PSM_HID_CONTROL)
- btpad_connection[slot].channels[0] = channel_id;
+ g_connected_pads[slot].channels[0] = channel_id;
else if (psm == PSM_HID_INTERRUPT)
- btpad_connection[slot].channels[1] = channel_id;
+ g_connected_pads[slot].channels[1] = channel_id;
else
ios_add_log_message("BTpad: Got unknown L2CAP PSM, ignoring (Slot: %d, PSM: %02X)", slot, psm);
- if (btpad_connection[slot].channels[0] && btpad_connection[slot].channels[1])
+ if (g_connected_pads[slot].channels[0] && g_connected_pads[slot].channels[1])
{
ios_add_log_message("BTpad: Got both L2CAP channels, requesting name (Slot: %d)", slot);
- btpad_queue_hci_remote_name_request(btpad_connection[slot].address, 0, 0, 0);
+ btpad_queue_hci_remote_name_request(g_connected_pads[slot].address, 0, 0, 0);
}
}
else
@@ -249,12 +253,12 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
{
ios_add_log_message("BTpad: Got new incoming connection (Slot: %d)", slot);
- memcpy(btpad_connection[slot].address, event_addr, sizeof(bd_addr_t));
+ memcpy(g_connected_pads[slot].address, event_addr, sizeof(bd_addr_t));
- btpad_connection[slot].has_address = true;
- btpad_connection[slot].handle = handle;
- btpad_connection[slot].state = BTPAD_CONNECTING;
- btpad_connection[slot].slot = slot;
+ g_connected_pads[slot].has_address = true;
+ g_connected_pads[slot].handle = handle;
+ g_connected_pads[slot].state = BTPAD_CONNECTING;
+ g_connected_pads[slot].slot = slot;
}
else break;
}
@@ -277,14 +281,14 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
ios_add_log_message("BTpad: Got %.200s (Slot: %d)", (char*)&packet[9], slot);
if (strncmp((char*)&packet[9], "PLAYSTATION(R)3 Controller", 26) == 0)
- btpad_iface[slot] = &btpad_ps3;
+ g_connected_pads[slot].interface = &hidpad_ps3;
else if (strncmp((char*)&packet[9], "Nintendo RVL-CNT-01", 19) == 0)
- btpad_iface[slot] = &btpad_wii;
+ g_connected_pads[slot].interface = &hidpad_wii;
- if (btpad_iface[slot])
+ if (g_connected_pads[slot].interface)
{
- btpad_device[slot] = btpad_iface[slot]->connect(&btpad_connection[slot]);
- btpad_connection[slot].state = BTPAD_CONNECTED;
+ g_connected_pads[slot].hidpad = g_connected_pads[slot].interface->connect(&g_connected_pads[slot], slot);
+ g_connected_pads[slot].state = BTPAD_CONNECTED;
}
}
break;
@@ -307,7 +311,7 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
const int32_t slot = btpad_find_slot_for(handle, 0);
if (slot >= 0)
{
- btpad_connection[slot].handle = 0;
+ g_connected_pads[slot].handle = 0;
btpad_disconnect_pad(slot);
ios_add_log_message("BTpad: Device disconnected (Slot: %d)", slot);
@@ -326,8 +330,14 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
break;
}
}
-
- for (int i = 0; i < MAX_PADS; i ++)
- if (btpad_device[i] && btpad_iface[i] && (btpad_connection[i].channels[0] == channel || btpad_connection[i].channels[1] == channel))
- btpad_iface[i]->packet_handler(btpad_device[i], packet_type, channel, packet, size);
+ else if (packet_type == L2CAP_DATA_PACKET)
+ {
+ for (int i = 0; i < MAX_PADS; i ++)
+ {
+ struct hidpad_connection* connection = &g_connected_pads[i];
+
+ if (connection->hidpad && connection->interface && (connection->channels[0] == channel || connection->channels[1] == channel))
+ connection->interface->packet_handler(connection->hidpad, packet, size);
+ }
+ }
}
diff --git a/apple/iOS/input/BTStack/btpad.h b/apple/iOS/bluetooth/btpad.h
similarity index 51%
rename from apple/iOS/input/BTStack/btpad.h
rename to apple/iOS/bluetooth/btpad.h
index 0bc70d060e..cf92d40ba7 100644
--- a/apple/iOS/input/BTStack/btpad.h
+++ b/apple/iOS/bluetooth/btpad.h
@@ -20,39 +20,4 @@
void btpad_set_inquiry_state(bool on);
-uint32_t btpad_get_buttons(uint32_t slot);
-int16_t btpad_get_axis(uint32_t slot, unsigned axis);
-
-// Private interface
-enum btpad_state { BTPAD_EMPTY, BTPAD_CONNECTING, BTPAD_CONNECTED };
-
-typedef struct
-{
- enum btpad_state state;
-
- uint32_t slot;
- uint16_t handle;
-
- bool has_address;
- bd_addr_t address;
-
- uint16_t channels[2]; //0: Control, 1: Interrupt
-
- bool connected;
-} btpad_connection_t;
-
-struct btpad_interface
-{
- void* (*connect)(const btpad_connection_t* connection);
- void (*disconnect)(void* device);
-
- uint32_t (*get_buttons)(void* device);
- int16_t (*get_axis)(void* device, unsigned axis);
-
- void (*packet_handler)(void* device, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
-};
-
-extern struct btpad_interface btpad_ps3;
-extern struct btpad_interface btpad_wii;
-
#endif
diff --git a/apple/iOS/input/BTStack/btpad_queue.c b/apple/iOS/bluetooth/btpad_queue.c
similarity index 100%
rename from apple/iOS/input/BTStack/btpad_queue.c
rename to apple/iOS/bluetooth/btpad_queue.c
diff --git a/apple/iOS/input/BTStack/btpad_queue.h b/apple/iOS/bluetooth/btpad_queue.h
similarity index 100%
rename from apple/iOS/input/BTStack/btpad_queue.h
rename to apple/iOS/bluetooth/btpad_queue.h
diff --git a/apple/iOS/input/BTStack/btstack/btstack.h b/apple/iOS/bluetooth/btstack/btstack.h
similarity index 100%
rename from apple/iOS/input/BTStack/btstack/btstack.h
rename to apple/iOS/bluetooth/btstack/btstack.h
diff --git a/apple/iOS/input/BTStack/btstack/hci_cmds.h b/apple/iOS/bluetooth/btstack/hci_cmds.h
similarity index 100%
rename from apple/iOS/input/BTStack/btstack/hci_cmds.h
rename to apple/iOS/bluetooth/btstack/hci_cmds.h
diff --git a/apple/iOS/input/BTStack/btstack/linked_list.h b/apple/iOS/bluetooth/btstack/linked_list.h
similarity index 100%
rename from apple/iOS/input/BTStack/btstack/linked_list.h
rename to apple/iOS/bluetooth/btstack/linked_list.h
diff --git a/apple/iOS/input/BTStack/btstack/run_loop.h b/apple/iOS/bluetooth/btstack/run_loop.h
similarity index 100%
rename from apple/iOS/input/BTStack/btstack/run_loop.h
rename to apple/iOS/bluetooth/btstack/run_loop.h
diff --git a/apple/iOS/input/BTStack/btstack/sdp_util.h b/apple/iOS/bluetooth/btstack/sdp_util.h
similarity index 100%
rename from apple/iOS/input/BTStack/btstack/sdp_util.h
rename to apple/iOS/bluetooth/btstack/sdp_util.h
diff --git a/apple/iOS/input/BTStack/btstack/utils.h b/apple/iOS/bluetooth/btstack/utils.h
similarity index 100%
rename from apple/iOS/input/BTStack/btstack/utils.h
rename to apple/iOS/bluetooth/btstack/utils.h
diff --git a/apple/iOS/browser.m b/apple/iOS/browser.m
index 5f70ed1d9a..c0aa8410e2 100644
--- a/apple/iOS/browser.m
+++ b/apple/iOS/browser.m
@@ -16,7 +16,7 @@
#include
#include
-#import "../RetroArch/RetroArch_Apple.h"
+#import "apple/common/RetroArch_Apple.h"
#import "views.h"
#include "conf/config_file.h"
@@ -29,50 +29,47 @@
{
NSString* _path;
NSMutableArray* _sectionNames;
+ id _delegate;
}
-+ (id)directoryListAtBrowseRoot
-{
- NSString* rootPath = RetroArch_iOS.get.documentsDirectory;
- NSString* ragPath = [rootPath stringByAppendingPathComponent:@"RetroArchGames"];
- RADirectoryList* list = [RADirectoryList directoryListForPath:path_is_directory(ragPath.UTF8String) ? ragPath : rootPath];
- return list;
-}
-+ (id)directoryListForPath:(NSString*)path
-{
- // NOTE: Don't remove or ignore this abstraction, this function will be expanded when cover art comes back.
- return [[RADirectoryList alloc] initWithPath:path];
-}
-
-- (id)initWithPath:(NSString*)path
+- (id)initWithPath:(NSString*)path delegate:(id)delegate
{
_path = path;
+ _delegate = delegate;
self = [super initWithStyle:UITableViewStylePlain];
self.title = path.lastPathComponent;
self.hidesHeaders = YES;
- NSMutableArray *toolbarButtons = [[NSMutableArray alloc] initWithCapacity:3];
+ NSMutableArray *toolbarButtons = [[NSMutableArray alloc] initWithCapacity:3];
- UIBarButtonItem *refreshButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:@selector(refresh)];
- refreshButton.style = UIBarButtonItemStyleBordered;
- [toolbarButtons addObject:refreshButton];
+ UIBarButtonItem *refreshButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:@selector(refresh)];
+ refreshButton.style = UIBarButtonItemStyleBordered;
+ [toolbarButtons addObject:refreshButton];
- UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
- [toolbarButtons addObject:flexibleSpace];
+ UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
+ [toolbarButtons addObject:flexibleSpace];
- UIBarButtonItem *newFolderButton = [[UIBarButtonItem alloc] initWithTitle:@"New Folder" style:UIBarButtonItemStyleBordered target:self action:@selector(createNewFolder)];
- [toolbarButtons addObject:newFolderButton];
+ UIBarButtonItem *newFolderButton = [[UIBarButtonItem alloc] initWithTitle:@"New Folder" style:UIBarButtonItemStyleBordered target:self action:@selector(createNewFolder)];
+ [toolbarButtons addObject:newFolderButton];
- [[[RetroArch_iOS get] toolbar] setItems:toolbarButtons];
- [self setToolbarItems:toolbarButtons];
-
- [self refresh];
+ [[[RetroArch_iOS get] toolbar] setItems:toolbarButtons];
+ [self setToolbarItems:toolbarButtons];
return self;
}
+- (void)viewWillAppear:(BOOL)animated
+{
+ [self refresh];
+}
+
+- (void)viewDidDisappear:(BOOL)animated
+{
+ [self reset];
+}
+
- (void)refresh
{
static const char sectionNames[28] = { '/', '#', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
@@ -104,7 +101,7 @@
section = contents->elems[i].attr.b ? 0 : section;
RADirectoryItem* item = RADirectoryItem.new;
- item.path = [NSString stringWithUTF8String:contents->elems[i].data];
+ item.path = @(contents->elems[i].data);
item.isDirectory = contents->elems[i].attr.b;
[sectionLists[section] addObject:item];
}
@@ -127,37 +124,27 @@
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
- RADirectoryItem* path = (RADirectoryItem*)[self itemForIndexPath:indexPath];
-
- if(path.isDirectory)
- [[RetroArch_iOS get] pushViewController:[RADirectoryList directoryListForPath:path.path] animated:YES];
- else
- {
- if (access(_path.UTF8String, R_OK | W_OK | X_OK))
- apple_display_alert(@"The directory containing the selected file has limited permissions. This may "
- "prevent zipped games from loading, and will cause some cores to not function.", 0);
-
- [[RetroArch_iOS get] pushViewController:[[RAModuleList alloc] initWithGame:path.path] animated:YES];
- }
+ [_delegate directoryList:self itemWasSelected:[self itemForIndexPath:indexPath]];
}
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
- RADirectoryItem* path = (RADirectoryItem*)[self itemForIndexPath:indexPath];
- static NSString *CellIdentifier = @"path";
+ static NSString* const cell_types[2] = { @"file", @"folder" };
+ static NSString* const icon_types[2] = { @"ic_file", @"ic_dir" };
+ static const UITableViewCellAccessoryType accessory_types[2] = { UITableViewCellAccessoryDetailDisclosureButton,
+ UITableViewCellAccessoryDisclosureIndicator };
+ RADirectoryItem* path = [self itemForIndexPath:indexPath];
+ uint32_t type_id = path.isDirectory ? 1 : 0;
- UITableViewCell* cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
- cell = (cell != nil) ? cell : [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
- cell.textLabel.text = [path.path lastPathComponent];
- cell.accessoryType = (path.isDirectory) ? UITableViewCellAccessoryDisclosureIndicator : UITableViewCellAccessoryNone;
-
- if (path.isDirectory) {
- cell.imageView.image = [UIImage imageNamed:@"ic_dir"];
- cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
- } else {
- cell.imageView.image = nil;
- cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
+ UITableViewCell* cell = [self.tableView dequeueReusableCellWithIdentifier:cell_types[type_id]];
+ if (!cell)
+ {
+ cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cell_types[type_id]];
+ cell.imageView.image = [UIImage imageNamed:icon_types[type_id]];
+ cell.accessoryType = accessory_types[type_id];
}
+
+ cell.textLabel.text = [path.path lastPathComponent];
return cell;
}
@@ -224,26 +211,25 @@
@implementation RAModuleList
{
- NSString* _game;
+ id _delegate;
}
-- (id)initWithGame:(NSString*)path
+- (id)initWithGame:(NSString*)path delegate:(id)delegate
{
self = [super initWithStyle:UITableViewStyleGrouped];
- [self setTitle:[path lastPathComponent]];
-
- _game = path;
+ [self setTitle:path ? [path lastPathComponent] : @"Cores"];
+ _delegate = delegate;
// Load the modules with their data
- NSArray* moduleList = [RAModuleInfo getModules];
+ NSArray* moduleList = apple_get_modules();
NSMutableArray* supported = [NSMutableArray arrayWithObject:@"Suggested Cores"];
NSMutableArray* other = [NSMutableArray arrayWithObject:@"Other Cores"];
for (RAModuleInfo* i in moduleList)
{
- if ([i supportsFileAtPath:_game]) [supported addObject:i];
- else [other addObject:i];
+ if (path && [i supportsFileAtPath:path]) [supported addObject:i];
+ else [other addObject:i];
}
if (supported.count > 1)
@@ -257,7 +243,7 @@
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
- apple_run_core((RAModuleInfo*)[self itemForIndexPath:indexPath], _game.UTF8String);
+ [_delegate moduleList:self itemWasSelected:[self itemForIndexPath:indexPath]];
}
- (void)infoButtonTapped:(id)sender
@@ -363,21 +349,8 @@
NSString *directoryPath = [currentDirectoryPath stringByAppendingPathComponent:cell.textLabel.text];
NSString *newPath = [directoryPath stringByAppendingPathComponent:fileName];
- BOOL didMove = [[NSFileManager defaultManager] moveItemAtPath:selectedFilePath toPath:newPath error:nil];
-
- if (didMove) {
- NSArray *viewsControllers = [[self presentingViewController] childViewControllers];
-
- // Searches for RADirectoryList instance and call the refresh method
- for (int i = 0; i < viewsControllers.count; i++) {
- if ([viewsControllers[i] isKindOfClass:[RADirectoryList class]]) {
- [viewsControllers[i] refresh];
- break;
- }
- }
- } else {
+ if (![[NSFileManager defaultManager] moveItemAtPath:selectedFilePath toPath:newPath error:nil])
apple_display_alert(@"It was not possible to move the file", 0);
- }
[self dismissViewController];
}
diff --git a/apple/iOS/input/BTStack/btpad_wii.c b/apple/iOS/input/BTStack/btpad_wii.c
deleted file mode 100644
index 8f4bbc569c..0000000000
--- a/apple/iOS/input/BTStack/btpad_wii.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/* RetroArch - A frontend for libretro.
- * Copyright (C) 2013 - Jason Fetters
- *
- * RetroArch is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Found-
- * ation, either version 3 of the License, or (at your option) any later version.
- *
- * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with RetroArch.
- * If not, see .
- */
-
-#include
-#include
-#include
-
-#include "boolean.h"
-#include "../../../RetroArch/rarch_wrapper.h"
-
-#include "btdynamic.h"
-#include "btpad.h"
-#include "wiimote.h"
-
-static void* btpad_wii_connect(const btpad_connection_t* connection)
-{
- struct wiimote_t* device = malloc(sizeof(struct wiimote_t));
- memset(device, 0, sizeof(struct wiimote_t));
-
- memcpy(device->addr, connection->address, BD_ADDR_LEN);
-
- device->unid = connection->slot;
- device->wiiMoteConHandle = connection->handle;
- device->c_source_cid = connection->channels[0];
- device->i_source_cid = connection->channels[1];
- device->state = WIIMOTE_STATE_CONNECTED;
- device->exp.type = EXP_NONE;
-
- wiimote_handshake(device, -1, NULL, -1);
-
- return device;
-}
-
-static void btpad_wii_disconnect(struct wiimote_t* device)
-{
-}
-
-static uint32_t btpad_wii_get_buttons(struct wiimote_t* device)
-{
- return device->btns | (device->exp.classic.btns << 16);
-}
-
-static int16_t btpad_wii_get_axis(struct wiimote_t* device, unsigned axis)
-{
-/* TODO
- if (device->.exp.type == EXP_CLASSIC)
- {
- switch (axis)
- {
- case 0: return device->wiimote.exp.classic.ljs.rx * 0x7FFF;
- case 1: return device->wiimote.exp.classic.ljs.ry * 0x7FFF;
- case 2: return device->wiimote.exp.classic.rjs.rx * 0x7FFF;
- case 3: return device->wiimote.exp.classic.rjs.ry * 0x7FFF;
- default: return 0;
- }
- }
-*/
-
- return 0;
-}
-
-static void btpad_wii_packet_handler(struct wiimote_t* device, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
-{
- if(packet_type == L2CAP_DATA_PACKET)
- {
- byte* msg = packet + 2;
-
- switch (packet[1])
- {
- case WM_RPT_BTN:
- {
- wiimote_pressed_buttons(device, msg);
- break;
- }
-
- case WM_RPT_READ:
- {
- wiimote_pressed_buttons(device, msg);
- wiimote_handshake(device, WM_RPT_READ, msg + 5, ((msg[2] & 0xF0) >> 4) + 1);
- break;
- }
-
- case WM_RPT_CTRL_STATUS:
- {
- wiimote_pressed_buttons(device, msg);
- wiimote_handshake(device,WM_RPT_CTRL_STATUS,msg,-1);
- break;
- }
-
- case WM_RPT_BTN_EXP:
- {
- wiimote_pressed_buttons(device, msg);
- wiimote_handle_expansion(device, msg+2);
- break;
- }
- }
-
- g_current_input_data.pad_buttons[device->unid] = btpad_wii_get_buttons(device);
- for (int i = 0; i < 4; i ++)
- g_current_input_data.pad_axis[device->unid][i] = btpad_wii_get_axis(device, i);
- }
-}
-
-struct btpad_interface btpad_wii =
-{
- (void*)&btpad_wii_connect,
- (void*)&btpad_wii_disconnect,
- (void*)&btpad_wii_get_buttons,
- (void*)&btpad_wii_get_axis,
- (void*)&btpad_wii_packet_handler
-};
diff --git a/apple/iOS/platform.h b/apple/iOS/platform.h
new file mode 100644
index 0000000000..d8675259c6
--- /dev/null
+++ b/apple/iOS/platform.h
@@ -0,0 +1,51 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2013 - Jason Fetters
+ * Copyright (C) 2011-2013 - Daniel De Matteis
+ *
+ * RetroArch is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with RetroArch.
+ * If not, see .
+ */
+
+#ifndef __RARCH_IOS_PLATFORM_H
+#define __RARCH_IOS_PLATFORM_H
+
+#include "views.h"
+
+@interface RAGameView : UIViewController
++ (RAGameView*)get;
+- (void)openPauseMenu;
+- (void)closePauseMenu;
+@end
+
+@interface RetroArch_iOS : UINavigationController
+
++ (RetroArch_iOS*)get;
+
+- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file;
+- (void)unloadingCore:(RAModuleInfo*)core;
+
+- (void)refreshSystemConfig;
+
+@property (strong, nonatomic) NSString* configDirectory; // e.g. /var/mobile/Documents/.RetroArch
+@property (strong, nonatomic) NSString* globalConfigFile; // e.g. /var/mobile/Documents/.RetroArch/retroarch.cfg
+@property (strong, nonatomic) NSString* coreDirectory; // e.g. /Applications/RetroArch.app/modules
+
+@property (strong, nonatomic) NSString* documentsDirectory; // e.g. /var/mobile/Documents
+@property (strong, nonatomic) NSString* systemDirectory; // e.g. /var/mobile/Documents/.RetroArch
+@property (strong, nonatomic) NSString* systemConfigPath; // e.g. /var/mobile/Documents/.RetroArch/frontend.cfg
+
+@end
+
+// modes are: keyboard, icade and btstack
+void ios_set_bluetooth_mode(NSString* mode);
+
+#endif
\ No newline at end of file
diff --git a/apple/iOS/platform.m b/apple/iOS/platform.m
new file mode 100644
index 0000000000..06e0c349b8
--- /dev/null
+++ b/apple/iOS/platform.m
@@ -0,0 +1,376 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2013 - Jason Fetters
+ *
+ * RetroArch is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with RetroArch.
+ * If not, see .
+ */
+
+#include
+#include
+
+#import "RetroArch_Apple.h"
+#include "rarch_wrapper.h"
+
+#include "apple/common/apple_input.h"
+
+#import "views.h"
+#include "bluetooth/btpad.h"
+#include "bluetooth/btdynamic.h"
+#include "bluetooth/btpad.h"
+
+#include "file.h"
+
+//#define HAVE_DEBUG_FILELOG
+void ios_set_bluetooth_mode(NSString* mode)
+{
+ apple_input_enable_icade([mode isEqualToString:@"icade"]);
+ btstack_set_poweron([mode isEqualToString:@"btstack"]);
+}
+
+// Input helpers: This is kept here because it needs objective-c
+static void handle_touch_event(NSArray* touches)
+{
+ const int numTouches = [touches count];
+ const float scale = [[UIScreen mainScreen] scale];
+
+ g_current_input_data.touch_count = 0;
+
+ for(int i = 0; i != numTouches && g_current_input_data.touch_count < MAX_TOUCHES; i ++)
+ {
+ UITouch* touch = [touches objectAtIndex:i];
+ const CGPoint coord = [touch locationInView:touch.view];
+
+ if (touch.phase != UITouchPhaseEnded && touch.phase != UITouchPhaseCancelled)
+ {
+ g_current_input_data.touches[g_current_input_data.touch_count ].screen_x = coord.x * scale;
+ g_current_input_data.touches[g_current_input_data.touch_count ++].screen_y = coord.y * scale;
+ }
+ }
+}
+
+@interface RApplication : UIApplication
+@end
+
+@implementation RApplication
+
+- (void)sendEvent:(UIEvent *)event
+{
+ [super sendEvent:event];
+
+ if ([[event allTouches] count])
+ handle_touch_event(event.allTouches.allObjects);
+ else if ([event respondsToSelector:@selector(_gsEvent)])
+ {
+ // Stolen from: http://nacho4d-nacho4d.blogspot.com/2012/01/catching-keyboard-events-in-ios.html
+ uint8_t* eventMem = (uint8_t*)(void*)CFBridgingRetain([event performSelector:@selector(_gsEvent)]);
+ int eventType = eventMem ? *(int*)&eventMem[8] : 0;
+
+ if (eventType == GSEVENT_TYPE_KEYDOWN || eventType == GSEVENT_TYPE_KEYUP)
+ apple_input_handle_key_event(*(uint16_t*)&eventMem[0x3C], eventType == GSEVENT_TYPE_KEYDOWN);
+
+ CFBridgingRelease(eventMem);
+ }
+}
+
+@end
+
+@implementation RetroArch_iOS
+{
+ UIWindow* _window;
+ NSString* _path;
+
+ bool _isGameTop, _isRomList;
+ uint32_t _settingMenusInBackStack;
+ uint32_t _enabledOrientations;
+}
+
++ (RetroArch_iOS*)get
+{
+ return (RetroArch_iOS*)[[UIApplication sharedApplication] delegate];
+}
+
+#pragma mark LIFECYCLE (UIApplicationDelegate)
+- (void)applicationDidFinishLaunching:(UIApplication *)application
+{
+ apple_platform = self;
+ self.delegate = self;
+
+ // Setup window
+ _window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
+ _window.rootViewController = self;
+ [_window makeKeyAndVisible];
+
+ // Build system paths and test permissions
+ self.documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
+ self.systemDirectory = [self.documentsDirectory stringByAppendingPathComponent:@".RetroArch"];
+ self.systemConfigPath = [self.systemDirectory stringByAppendingPathComponent:@"frontend.cfg"];
+
+ self.configDirectory = self.systemDirectory;
+ self.globalConfigFile = [NSString stringWithFormat:@"%@/retroarch.cfg", self.configDirectory];
+ self.coreDirectory = [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"modules"];
+
+ if (!path_make_and_check_directory(self.documentsDirectory.UTF8String, 0755, R_OK | W_OK | X_OK))
+ apple_display_alert([NSString stringWithFormat:@"Failed to create or access base directory: %@", self.documentsDirectory], 0);
+ else if (!path_make_and_check_directory(self.systemDirectory.UTF8String, 0755, R_OK | W_OK | X_OK))
+ apple_display_alert([NSString stringWithFormat:@"Failed to create or access system directory: %@", self.systemDirectory], 0);
+ else
+ [self beginBrowsingForFile];
+
+
+ // Warn if there are no cores present
+ if (apple_get_modules().count == 0)
+ apple_display_alert(@"No libretro cores were found. You will not be able to play any games.", 0);
+}
+
+- (void)applicationDidBecomeActive:(UIApplication *)application
+{
+ apple_exit_stasis(false);
+}
+
+- (void)applicationWillResignActive:(UIApplication *)application
+{
+ apple_enter_stasis();
+}
+
+#pragma mark Frontend Browsing Logic
+- (void)beginBrowsingForFile
+{
+ NSString* rootPath = RetroArch_iOS.get.documentsDirectory;
+ NSString* ragPath = [rootPath stringByAppendingPathComponent:@"RetroArchGames"];
+ NSString* target = path_is_directory(ragPath.UTF8String) ? ragPath : rootPath;
+
+ [self pushViewController:[[RADirectoryList alloc] initWithPath:target delegate:self] animated:YES];
+
+ [self refreshSystemConfig];
+ if (apple_use_tv_mode)
+ apple_run_core(nil, 0);
+
+}
+
+- (bool)directoryList:(id)list itemWasSelected:(RADirectoryItem*)path
+{
+ if(path.isDirectory)
+ [[RetroArch_iOS get] pushViewController:[[RADirectoryList alloc] initWithPath:path.path delegate:self] animated:YES];
+ else
+ {
+ _path = path.path;
+
+ if (access([path.path stringByDeletingLastPathComponent].UTF8String, R_OK | W_OK | X_OK))
+ apple_display_alert(@"The directory containing the selected file has limited permissions. This may "
+ "prevent zipped games from loading, and will cause some cores to not function.", 0);
+
+ [[RetroArch_iOS get] pushViewController:[[RAModuleList alloc] initWithGame:path.path delegate:self] animated:YES];
+ }
+
+ return true;
+}
+
+- (bool)moduleList:(id)list itemWasSelected:(RAModuleInfo*)module
+{
+ apple_run_core(module, _path.UTF8String);
+ return true;
+}
+
+// UINavigationControllerDelegate
+- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
+{
+ _isGameTop = [viewController isKindOfClass:[RAGameView class]];
+ _isRomList = [viewController isKindOfClass:[RADirectoryList class]];
+
+ [[UIApplication sharedApplication] setStatusBarHidden:_isGameTop withAnimation:UIStatusBarAnimationNone];
+ [[UIApplication sharedApplication] setIdleTimerDisabled:_isGameTop];
+
+ self.navigationBarHidden = _isGameTop;
+ [self setToolbarHidden:!_isRomList animated:YES];
+ self.topViewController.navigationItem.rightBarButtonItem = [self createSettingsButton];
+}
+
+// UINavigationController: Never animate when pushing onto, or popping, an RAGameView
+- (void)pushViewController:(UIViewController*)theView animated:(BOOL)animated
+{
+ if ([theView respondsToSelector:@selector(isSettingsView)] && [(id)theView isSettingsView])
+ _settingMenusInBackStack ++;
+
+ [super pushViewController:theView animated:animated && !_isGameTop];
+}
+
+- (UIViewController*)popViewControllerAnimated:(BOOL)animated
+{
+ if ([self.topViewController respondsToSelector:@selector(isSettingsView)] && [(id)self.topViewController isSettingsView])
+ _settingMenusInBackStack --;
+
+ return [super popViewControllerAnimated:animated && !_isGameTop];
+}
+
+// NOTE: This version only runs on iOS6
+- (NSUInteger)supportedInterfaceOrientations
+{
+ return _isGameTop ? _enabledOrientations
+ : UIInterfaceOrientationMaskAll;
+}
+
+// NOTE: This version runs on iOS2-iOS5, but not iOS6
+- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
+{
+ if (_isGameTop)
+ switch (interfaceOrientation)
+ {
+ case UIInterfaceOrientationPortrait:
+ return (_enabledOrientations & UIInterfaceOrientationMaskPortrait);
+ case UIInterfaceOrientationPortraitUpsideDown:
+ return (_enabledOrientations & UIInterfaceOrientationMaskPortraitUpsideDown);
+ case UIInterfaceOrientationLandscapeLeft:
+ return (_enabledOrientations & UIInterfaceOrientationMaskLandscapeLeft);
+ case UIInterfaceOrientationLandscapeRight:
+ return (_enabledOrientations & UIInterfaceOrientationMaskLandscapeRight);
+ }
+
+ return YES;
+}
+
+
+#pragma mark RetroArch_Platform
+- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file
+{
+ [self pushViewController:RAGameView.get animated:NO];
+ [RASettingsList refreshModuleConfig:core];
+
+ btpad_set_inquiry_state(false);
+
+ [self refreshSystemConfig];
+}
+
+- (void)unloadingCore:(RAModuleInfo*)core
+{
+ [self popToViewController:[RAGameView get] animated:NO];
+ [self popViewControllerAnimated:NO];
+
+ btpad_set_inquiry_state(true);
+}
+
+#pragma mark FRONTEND CONFIG
+- (void)refreshSystemConfig
+{
+ // Read load time settings
+ config_file_t* conf = config_file_new([self.systemConfigPath UTF8String]);
+
+ if (conf)
+ {
+ // Get enabled orientations
+ static const struct { const char* setting; uint32_t orientation; } orientationSettings[4] =
+ {
+ { "ios_allow_portrait", UIInterfaceOrientationMaskPortrait },
+ { "ios_allow_portrait_upside_down", UIInterfaceOrientationMaskPortraitUpsideDown },
+ { "ios_allow_landscape_left", UIInterfaceOrientationMaskLandscapeLeft },
+ { "ios_allow_landscape_right", UIInterfaceOrientationMaskLandscapeRight }
+ };
+
+ _enabledOrientations = 0;
+
+ for (int i = 0; i < 4; i ++)
+ {
+ bool enabled = false;
+ bool found = config_get_bool(conf, orientationSettings[i].setting, &enabled);
+
+ if (!found || enabled)
+ _enabledOrientations |= orientationSettings[i].orientation;
+ }
+
+ // Setup bluetooth mode
+ ios_set_bluetooth_mode(objc_get_value_from_config(conf, @"ios_btmode", @"keyboard"));
+
+ bool val;
+ apple_use_tv_mode = config_get_bool(conf, "ios_tv_mode", &val) && val;
+
+ config_file_free(conf);
+ }
+}
+
+#pragma mark PAUSE MENU
+- (UIBarButtonItem*)createSettingsButton
+{
+ if (_settingMenusInBackStack == 0)
+ return [[UIBarButtonItem alloc]
+ initWithTitle:@"Settings"
+ style:UIBarButtonItemStyleBordered
+ target:[RetroArch_iOS get]
+ action:@selector(showSystemSettings)];
+
+ else
+ return nil;
+}
+
+- (IBAction)showPauseMenu:(id)sender
+{
+ if (apple_is_running && !apple_is_paused && _isGameTop)
+ {
+ apple_is_paused = true;
+ [[RAGameView get] openPauseMenu];
+
+ btpad_set_inquiry_state(true);
+ }
+}
+
+- (IBAction)basicEvent:(id)sender
+{
+ if (apple_is_running)
+ apple_frontend_post_event(&apple_event_basic_command, ((UIView*)sender).tag);
+
+ [self closePauseMenu:sender];
+}
+
+- (IBAction)chooseState:(id)sender
+{
+ if (apple_is_running)
+ apple_frontend_post_event(apple_event_set_state_slot, (void*)((UISegmentedControl*)sender).selectedSegmentIndex);
+}
+
+- (IBAction)showRGUI:(id)sender
+{
+ if (apple_is_running)
+ apple_frontend_post_event(apple_event_show_rgui, 0);
+
+ [self closePauseMenu:sender];
+}
+
+- (IBAction)closePauseMenu:(id)sender
+{
+ [[RAGameView get] closePauseMenu];
+ apple_is_paused = false;
+
+ btpad_set_inquiry_state(false);
+}
+
+- (IBAction)showSettings
+{
+ [self pushViewController:[[RASettingsList alloc] initWithModule:apple_core] animated:YES];
+}
+
+- (IBAction)showSystemSettings
+{
+ [self pushViewController:[RASystemSettingsList new] animated:YES];
+}
+
+@end
+
+int main(int argc, char *argv[])
+{
+ @autoreleasepool {
+#if defined(HAVE_DEBUG_FILELOG) && (TARGET_IPHONE_SIMULATOR == 0)
+ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+ NSString *documentsDirectory = [paths objectAtIndex:0];
+ NSString *logPath = [documentsDirectory stringByAppendingPathComponent:@"console_stdout.log"];
+ freopen([logPath cStringUsingEncoding:NSASCIIStringEncoding], "a", stdout);
+ freopen([logPath cStringUsingEncoding:NSASCIIStringEncoding], "a", stderr);
+#endif
+ return UIApplicationMain(argc, argv, NSStringFromClass([RApplication class]), NSStringFromClass([RetroArch_iOS class]));
+ }
+}
diff --git a/apple/iOS/settings.m b/apple/iOS/settings.m
index 65b4c025eb..11d3b73509 100644
--- a/apple/iOS/settings.m
+++ b/apple/iOS/settings.m
@@ -13,13 +13,13 @@
* If not, see .
*/
-#import "../RetroArch/RetroArch_Apple.h"
+#import "apple/common/RetroArch_Apple.h"
#import "views.h"
-#include "../RetroArch/apple_input.h"
-#include "../RetroArch/keycode.h"
-#include "input/BTStack/btdynamic.h"
-#include "input/BTStack/btpad.h"
+#include "apple/common/apple_input.h"
+#include "apple/common/keycode.h"
+#include "bluetooth/btdynamic.h"
+#include "bluetooth/btpad.h"
enum SettingTypes
{
@@ -28,34 +28,79 @@ enum SettingTypes
};
@interface RASettingData : NSObject
-@property enum SettingTypes type;
+{
+ @public
+ enum SettingTypes type;
-@property (strong) NSString* label;
-@property (strong) NSString* name;
-@property (strong) NSString* value;
+ NSString* label; // < The label displayed in the settings menu
+ NSString* name; // < The key name of the value in the config file
+ NSString* value; // < The current state of the setting
-@property (strong) NSString* path;
-@property (strong) NSArray* subValues;
-@property (strong) NSMutableArray* msubValues;
+ uint32_t player; // < The player that a ButtonSetting represents
+ NSString* button_bind; // < The Gamepad button binding string
+ NSString* axis_bind; // < The Gamepad axis binding string
+
+ NSString* path; // < The base path for FileListSettings
+ NSArray* subValues; // < The available options for EnumerationSettings and FileListSettings
+ bool haveNoneOption; // < Determines if a 'None' option is added to an Enumeration or FileList
+ bool haveDescriptions; // < Determines if subValues containts friendly descriptions for each value
+
+ double rangeMin; // < The mininum value of a range setting
+ double rangeMax; // < The maximum value of a range setting
+
+ void (*changed)(RASettingData* action);
+ void (*reload)(RASettingData* action, id userdata);
+}
-@property double rangeMin;
-@property double rangeMax;
+- (void)setValue:(NSString*)aValue;
-@property uint32_t player;
-
-@property bool haveNoneOption;
-
-- (id)initWithType:(enum SettingTypes)aType label:(NSString*)aLabel name:(NSString*)aName;
@end
@implementation RASettingData
- (id)initWithType:(enum SettingTypes)aType label:(NSString*)aLabel name:(NSString*)aName
{
- self.type = aType;
- self.label = aLabel;
- self.name = aName;
+ type = aType;
+ label = aLabel;
+ name = aName;
return self;
}
+
+- (void)setValue:(NSString*)aValue;
+{
+ value = aValue;
+
+ if (changed)
+ changed(self);
+}
+
+- (uint32_t)enumerationCount
+{
+ return subValues.count / (haveDescriptions ? 2 : 1);
+}
+
+- (NSString*)valueForEnumerationIndex:(uint32_t)index
+{
+ return subValues[index * (haveDescriptions ? 2 : 1)];
+}
+
+- (NSString*)labelForEnumerationIndex:(uint32_t)index
+{
+ return subValues[index * (haveDescriptions ? 2 : 1) + (haveDescriptions ? 1 : 0)];
+}
+
+- (NSString*)labelForEnumerationValue
+{
+ const uint32_t count = self.enumerationCount;
+
+ for (int i = 0; haveDescriptions && i < count; i ++)
+ {
+ if ([value isEqualToString:subValues[i * 2]])
+ return subValues[i * 2 + 1];
+ }
+
+ return value;
+}
+
@end
// Helper view definitions
@@ -71,7 +116,7 @@ enum SettingTypes
static RASettingData* boolean_setting(config_file_t* config, NSString* name, NSString* label, NSString* defaultValue)
{
RASettingData* result = [[RASettingData alloc] initWithType:BooleanSetting label:label name:name];
- result.value = objc_get_value_from_config(config, name, defaultValue);
+ result->value = objc_get_value_from_config(config, name, defaultValue);
return result;
}
@@ -80,27 +125,26 @@ static RASettingData* button_setting(config_file_t* config, uint32_t player, NSS
NSString* realname = player ? [NSString stringWithFormat:@"input_player%d_%@", player, name] : name;
RASettingData* result = [[RASettingData alloc] initWithType:ButtonSetting label:label name:realname];
- result.msubValues = [NSMutableArray arrayWithObjects:
- objc_get_value_from_config(config, realname, defaultValue),
- objc_get_value_from_config(config, [realname stringByAppendingString:@"_btn"], @"nul"),
- objc_get_value_from_config(config, [realname stringByAppendingString:@"_axis"], @"nul"),
- nil];
- result.player = player ? player - 1 : 0;
+ result->player = player ? player - 1 : 0;
+ result->value = objc_get_value_from_config(config, realname, defaultValue);
+ result->button_bind = objc_get_value_from_config(config, [realname stringByAppendingString:@"_btn"], @"nul");
+ result->axis_bind = objc_get_value_from_config(config, [realname stringByAppendingString:@"_axis"], @"nul");
return result;
}
static RASettingData* group_setting(NSString* label, NSArray* settings)
{
RASettingData* result = [[RASettingData alloc] initWithType:GroupSetting label:label name:nil];
- result.subValues = settings;
+ result->subValues = settings;
return result;
}
-static RASettingData* enumeration_setting(config_file_t* config, NSString* name, NSString* label, NSString* defaultValue, NSArray* values)
+static RASettingData* enumeration_setting(config_file_t* config, NSString* name, NSString* label, NSString* defaultValue, NSArray* values, bool haveDescriptions)
{
RASettingData* result = [[RASettingData alloc] initWithType:EnumerationSetting label:label name:name];
- result.value = objc_get_value_from_config(config, name, defaultValue);
- result.subValues = values;
+ result->value = objc_get_value_from_config(config, name, defaultValue);
+ result->subValues = values;
+ result->haveDescriptions = haveDescriptions;
return result;
}
@@ -113,19 +157,19 @@ static RASettingData* subpath_setting(config_file_t* config, NSString* name, NSS
values = [values pathsMatchingExtensions:[NSArray arrayWithObject:extension]];
RASettingData* result = [[RASettingData alloc] initWithType:FileListSetting label:label name:name];
- result.value = value;
- result.subValues = values;
- result.path = path;
- result.haveNoneOption = true;
+ result->value = value;
+ result->subValues = values;
+ result->path = path;
+ result->haveNoneOption = true;
return result;
}
static RASettingData* range_setting(config_file_t* config, NSString* name, NSString* label, NSString* defaultValue, double minValue, double maxValue)
{
RASettingData* result = [[RASettingData alloc] initWithType:RangeSetting label:label name:name];
- result.value = objc_get_value_from_config(config, name, defaultValue);
- result.rangeMin = minValue;
- result.rangeMax = maxValue;
+ result->value = objc_get_value_from_config(config, name, defaultValue);
+ result->rangeMin = minValue;
+ result->rangeMax = maxValue;
return result;
}
@@ -133,8 +177,8 @@ static RASettingData* aspect_setting(config_file_t* config, NSString* label)
{
// Why does this need to be so difficult?
- RASettingData* result = [[RASettingData alloc] initWithType:AspectSetting label:label name:@"fram"];
- result.subValues = [NSArray arrayWithObjects:@"Fill Screen", @"Game Aspect", @"Pixel Aspect", @"4:3", @"16:9", nil];
+ RASettingData* result = [[RASettingData alloc] initWithType:AspectSetting label:label name:@""];
+ result->subValues = [NSArray arrayWithObjects:@"Fill Screen", @"Game Aspect", @"Pixel Aspect", @"4:3", @"16:9", nil];
bool videoForceAspect = true;
bool videoAspectAuto = false;
@@ -148,19 +192,20 @@ static RASettingData* aspect_setting(config_file_t* config, NSString* label)
}
if (!videoForceAspect)
- result.value = @"Fill Screen";
+ result->value = @"Fill Screen";
else if (videoAspect < 0.0)
- result.value = videoAspectAuto ? @"Game Aspect" : @"Pixel Aspect";
+ result->value = videoAspectAuto ? @"Game Aspect" : @"Pixel Aspect";
else
- result.value = (videoAspect < 1.5) ? @"4:3" : @"16:9";
+ result->value = (videoAspect < 1.5) ? @"4:3" : @"16:9";
return result;
}
-static RASettingData* custom_action(NSString* action, NSString* value, id data)
+static RASettingData* custom_action(NSString* action, NSString* value, id data, void (*reload_func)(RASettingData* action, id userdata))
{
RASettingData* result = [[RASettingData alloc] initWithType:CustomAction label:action name:nil];
- result.value = value;
+ result->value = value;
+ result->reload = reload_func;
if (data != nil)
objc_setAssociatedObject(result, "USERDATA", data, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
@@ -168,25 +213,36 @@ static RASettingData* custom_action(NSString* action, NSString* value, id data)
return result;
}
+// This adds a change notify function to a setting and returns it; done this way so it can be used in NSArray
+// init lists.
+static RASettingData* change_notify(RASettingData* setting, void (*change_func)(RASettingData* setting))
+{
+ setting->changed = change_func;
+ return setting;
+}
+
static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
{
+ // Only player 1 should have default key bindings
+ #define DEFKEY(val) (player == 1) ? val : @"nul"
+
return [NSArray arrayWithObjects:
[NSArray arrayWithObjects:[NSString stringWithFormat:@"Player %d", player],
- button_setting(config, player, @"up", @"Up", @"up"),
- button_setting(config, player, @"down", @"Down", @"down"),
- button_setting(config, player, @"left", @"Left", @"left"),
- button_setting(config, player, @"right", @"Right", @"right"),
+ button_setting(config, player, @"up", @"Up", DEFKEY(@"up")),
+ button_setting(config, player, @"down", @"Down", DEFKEY(@"down")),
+ button_setting(config, player, @"left", @"Left", DEFKEY(@"left")),
+ button_setting(config, player, @"right", @"Right", DEFKEY(@"right")),
- button_setting(config, player, @"start", @"Start", @"enter"),
- button_setting(config, player, @"select", @"Select", @"rshift"),
+ button_setting(config, player, @"start", @"Start", DEFKEY(@"enter")),
+ button_setting(config, player, @"select", @"Select", DEFKEY(@"rshift")),
- button_setting(config, player, @"b", @"B", @"z"),
- button_setting(config, player, @"a", @"A", @"x"),
- button_setting(config, player, @"x", @"X", @"s"),
- button_setting(config, player, @"y", @"Y", @"a"),
+ button_setting(config, player, @"b", @"B", DEFKEY(@"z")),
+ button_setting(config, player, @"a", @"A", DEFKEY(@"x")),
+ button_setting(config, player, @"x", @"X", DEFKEY(@"s")),
+ button_setting(config, player, @"y", @"Y", DEFKEY(@"a")),
- button_setting(config, player, @"l", @"L", @"q"),
- button_setting(config, player, @"r", @"R", @"w"),
+ button_setting(config, player, @"l", @"L", DEFKEY(@"q")),
+ button_setting(config, player, @"r", @"R", DEFKEY(@"w")),
button_setting(config, player, @"l2", @"L2", @"nul"),
button_setting(config, player, @"r2", @"R2", @"nul"),
button_setting(config, player, @"l3", @"L3", @"nul"),
@@ -219,7 +275,7 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
- (id)initWithModule:(RAModuleInfo*)module
{
_module = module;
- _configPath = RetroArch_iOS.get.retroarchConfigPath;
+ _configPath = _module ? _module.configFile : apple_platform.globalConfigFile;
config_file_t* config = config_file_new([_configPath UTF8String]);
@@ -228,7 +284,8 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
NSArray* settings = [NSArray arrayWithObjects:
[NSArray arrayWithObjects:@"Core",
- custom_action(@"Core Info", nil, nil),
+ custom_action(@"Core Info", nil, nil, 0),
+ _module.hasCustomConfig ? custom_action(@"Delete Custom Config", nil, nil, 0) : nil,
nil],
[NSArray arrayWithObjects:@"Video",
@@ -305,37 +362,71 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
if (config)
{
config_set_string(config, "system_directory", [[RetroArch_iOS get].systemDirectory UTF8String]);
+ config_set_string(config, "savefile_directory", [[RetroArch_iOS get].systemDirectory UTF8String]);
+ config_set_string(config, "savestate_directory", [[RetroArch_iOS get].systemDirectory UTF8String]);
[self writeSettings:nil toConfig:config];
config_file_write(config, [_configPath UTF8String]);
config_file_free(config);
}
- [[RetroArch_iOS get] refreshConfig];
+ apple_refresh_config();
}
}
- (void)handleCustomAction:(RASettingData*)setting
{
- if ([@"Core Info" isEqualToString:setting.label])
+ if ([@"Core Info" isEqualToString:setting->label])
[[RetroArch_iOS get] pushViewController:[[RAModuleInfoList alloc] initWithModuleInfo:_module] animated:YES];
+ else if([@"Delete Custom Config" isEqualToString:setting->label])
+ {
+ [_module deleteCustomConfig];
+ _cancelSave = true;
+ [self.navigationController popViewControllerAnimated:YES];
+ }
}
@end
+#pragma mark System Settings
+
+static void reload_core_config_state(RASettingData* action, RAModuleInfo* userdata)
+{
+ [action setValue:userdata.hasCustomConfig ? @"[Custom]" : @"[Global]"];
+}
+
+static void bluetooth_option_changed(RASettingData* setting)
+{
+ ios_set_bluetooth_mode(setting->value);
+}
+
@implementation RASystemSettingsList
- (id)init
{
config_file_t* config = config_file_new([[RetroArch_iOS get].systemConfigPath UTF8String]);
+
+ NSMutableArray* modules = [NSMutableArray array];
+ [modules addObject:@"Cores"];
+ [modules addObject:custom_action(@"Global Core Config", nil, nil, 0)];
+
+ NSArray* moduleList = apple_get_modules();
+ for (RAModuleInfo* i in moduleList)
+ {
+ [modules addObject:custom_action(i.description, nil, i, reload_core_config_state)];
+ }
+
+
+ NSArray* bluetoothOptions = [NSArray arrayWithObjects:@"keyboard", @"Keyboard",
+ @"icade", @"iCade Device",
+ btstack_try_load() ? @"btstack" : nil, @"WiiMote/SixAxis (BTstack)",
+ nil];
NSArray* settings = [NSArray arrayWithObjects:
[NSArray arrayWithObjects:@"Frontend",
- custom_action(@"Diagnostic Log", nil, nil),
+ custom_action(@"Diagnostic Log", nil, nil, 0),
boolean_setting(config, @"ios_tv_mode", @"TV Mode", @"false"),
nil],
[NSArray arrayWithObjects:@"Bluetooth",
- // TODO: Note that with this turned off the native bluetooth is expected to be a real keyboard
- boolean_setting(config, @"ios_use_icade", @"Native BT is iCade", @"false"),
- btstack_try_load() ? boolean_setting(config, @"ios_use_btstack", @"Enable BTstack", @"false") : nil,
+ change_notify(enumeration_setting(config, @"ios_btmode", @"Mode", @"keyboard", bluetoothOptions, true), bluetooth_option_changed),
nil],
[NSArray arrayWithObjects:@"Orientations",
boolean_setting(config, @"ios_allow_portrait", @"Portrait", @"true"),
@@ -343,9 +434,7 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
boolean_setting(config, @"ios_allow_landscape_left", @"Landscape Left", @"true"),
boolean_setting(config, @"ios_allow_landscape_right", @"Landscape Right", @"true"),
nil],
- [NSArray arrayWithObjects:@"Cores",
- custom_action(@"Core Configuration", nil, nil),
- nil],
+ modules,
nil
];
@@ -356,6 +445,12 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
return self;
}
+- (void)viewDidAppear:(BOOL)animated
+{
+ [self.tableView reloadData];
+ [super viewDidAppear:animated];
+}
+
- (void)dealloc
{
config_file_t* config = config_file_new([[RetroArch_iOS get].systemConfigPath UTF8String]);
@@ -375,12 +470,49 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
- (void)handleCustomAction:(RASettingData*)setting
{
- if ([@"Diagnostic Log" isEqualToString:setting.label])
+ if ([@"Diagnostic Log" isEqualToString:setting->label])
[[RetroArch_iOS get] pushViewController:[RALogView new] animated:YES];
- else if ([@"Enable BTstack" isEqualToString:setting.label])
- btstack_set_poweron([setting.value isEqualToString:@"true"]);
- else if([@"Core Configuration" isEqualToString:setting.label])
+ else if ([@"Enable BTstack" isEqualToString:setting->label])
+ btstack_set_poweron([setting->value isEqualToString:@"true"]);
+ else if([@"Global Core Config" isEqualToString:setting->label])
[RetroArch_iOS.get pushViewController:[[RASettingsList alloc] initWithModule:nil] animated:YES];
+ else
+ {
+ RAModuleInfo* data = (RAModuleInfo*)objc_getAssociatedObject(setting, "USERDATA");
+ if (data)
+ {
+ if (!data.hasCustomConfig)
+ {
+ UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"RetroArch"
+ message:@"No custom configuration for this core exists, "
+ "would you like to create one?"
+ delegate:self
+ cancelButtonTitle:@"No"
+ otherButtonTitles:@"Yes", nil];
+ objc_setAssociatedObject(alert, "MODULE", data, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+ [alert show];
+ }
+ else
+ [RetroArch_iOS.get pushViewController:[[RASettingsList alloc] initWithModule:data] animated:YES];
+ }
+ }
+}
+
+- (void)alertView:(UIAlertView*)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex
+{
+ RAModuleInfo* data = (RAModuleInfo*)objc_getAssociatedObject(alertView, "MODULE");
+
+ if (data)
+ {
+ if (buttonIndex == alertView.firstOtherButtonIndex)
+ {
+ [data createCustomConfig];
+ [self.tableView reloadData];
+ }
+
+ [RetroArch_iOS.get pushViewController:[[RASettingsList alloc] initWithModule:data] animated:YES];
+ }
+
}
@end
@@ -420,35 +552,35 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
{
RASettingData* setting = [group objectAtIndex:j];
- switch (setting.type)
+ switch (setting->type)
{
case GroupSetting:
- [self writeSettings:setting.subValues toConfig:config];
+ [self writeSettings:setting->subValues toConfig:config];
break;
case FileListSetting:
- if ([setting.value length] > 0)
- config_set_string(config, [setting.name UTF8String], [[setting.path stringByAppendingPathComponent:setting.value] UTF8String]);
+ if ([setting->value length] > 0)
+ config_set_string(config, [setting->name UTF8String], [[setting->path stringByAppendingPathComponent:setting->value] UTF8String]);
else
- config_set_string(config, [setting.name UTF8String], "");
+ config_set_string(config, [setting->name UTF8String], "");
break;
case ButtonSetting:
- if (setting.msubValues[0])
- config_set_string(config, [setting.name UTF8String], [setting.msubValues[0] UTF8String]);
- if (setting.msubValues[1])
- config_set_string(config, [[setting.name stringByAppendingString:@"_btn"] UTF8String], [setting.msubValues[1] UTF8String]);
- if (setting.msubValues[2])
- config_set_string(config, [[setting.name stringByAppendingString:@"_axis"] UTF8String], [setting.msubValues[2] UTF8String]);
+ if (setting->value)
+ config_set_string(config, [setting->name UTF8String], [setting->value UTF8String]);
+ if (setting->button_bind)
+ config_set_string(config, [[setting->name stringByAppendingString:@"_btn"] UTF8String], [setting->button_bind UTF8String]);
+ if (setting->axis_bind)
+ config_set_string(config, [[setting->name stringByAppendingString:@"_axis"] UTF8String], [setting->axis_bind UTF8String]);
break;
case AspectSetting:
- config_set_string(config, "video_force_aspect", [@"Fill Screen" isEqualToString:setting.value] ? "false" : "true");
- config_set_string(config, "video_aspect_ratio_auto", [@"Game Aspect" isEqualToString:setting.value] ? "true" : "false");
+ config_set_string(config, "video_force_aspect", [@"Fill Screen" isEqualToString:setting->value] ? "false" : "true");
+ config_set_string(config, "video_aspect_ratio_auto", [@"Game Aspect" isEqualToString:setting->value] ? "true" : "false");
config_set_string(config, "video_aspect_ratio", "-1.0");
- if([@"4:3" isEqualToString:setting.value])
+ if([@"4:3" isEqualToString:setting->value])
config_set_string(config, "video_aspect_ratio", "1.33333333");
- else if([@"16:9" isEqualToString:setting.value])
+ else if([@"16:9" isEqualToString:setting->value])
config_set_string(config, "video_aspect_ratio", "1.77777777");
break;
@@ -456,7 +588,7 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
break;
default:
- config_set_string(config, [setting.name UTF8String], [setting.value UTF8String]);
+ config_set_string(config, [setting->name UTF8String], [setting->value UTF8String]);
break;
}
}
@@ -467,7 +599,7 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
{
RASettingData* setting = (RASettingData*)[self itemForIndexPath:indexPath];
- switch (setting.type)
+ switch (setting->type)
{
case EnumerationSetting:
case FileListSetting:
@@ -480,7 +612,7 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
break;
case GroupSetting:
- [[RetroArch_iOS get] pushViewController:[[RASettingsSubList alloc] initWithSettings:setting.subValues title:setting.label] animated:YES];
+ [[RetroArch_iOS get] pushViewController:[[RASettingsSubList alloc] initWithSettings:setting->subValues title:setting->label] animated:YES];
break;
default:
@@ -493,7 +625,7 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
- (void)handleBooleanSwitch:(UISwitch*)swt
{
RASettingData* setting = objc_getAssociatedObject(swt, "SETTING");
- setting.value = (swt.on ? @"true" : @"false");
+ [setting setValue:swt.on ? @"true" : @"false"];
[self handleCustomAction:setting];
}
@@ -501,7 +633,7 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
- (void)handleSlider:(UISlider*)sld
{
RASettingData* setting = objc_getAssociatedObject(sld, "SETTING");
- setting.value = [NSString stringWithFormat:@"%f", sld.value];
+ [setting setValue:[NSString stringWithFormat:@"%f", sld.value]];
[self handleCustomAction:setting];
}
@@ -512,7 +644,7 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
UITableViewCell* cell = nil;
- switch (setting.type)
+ switch (setting->type)
{
case BooleanSetting:
{
@@ -529,10 +661,10 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
}
- cell.textLabel.text = setting.label;
+ cell.textLabel.text = setting->label;
UISwitch* swt = (UISwitch*)cell.accessoryView;
- swt.on = [setting.value isEqualToString:@"true"];
+ swt.on = [setting->value isEqualToString:@"true"];
objc_setAssociatedObject(swt, "SETTING", setting, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
return cell;
@@ -554,12 +686,12 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
}
- cell.textLabel.text = setting.label;
+ cell.textLabel.text = setting->label;
UISlider* sld = (UISlider*)cell.accessoryView;
- sld.minimumValue = setting.rangeMin;
- sld.maximumValue = setting.rangeMax;
- sld.value = [setting.value doubleValue];
+ sld.minimumValue = setting->rangeMin;
+ sld.maximumValue = setting->rangeMax;
+ sld.value = [setting->value doubleValue];
objc_setAssociatedObject(sld, "SETTING", setting, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
return cell;
@@ -575,16 +707,21 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"default"];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
-
- cell.textLabel.text = setting.label;
+
+ if (setting->reload)
+ setting->reload(setting, objc_getAssociatedObject(setting, "USERDATA"));
+
+ cell.textLabel.text = setting->label;
- if (setting.type != ButtonSetting)
- cell.detailTextLabel.text = setting.value;
- else
+ if (setting->type == ButtonSetting)
cell.detailTextLabel.text = [NSString stringWithFormat:@"[KB:%@] [JS:%@] [AX:%@]",
- [setting.msubValues[0] length] ? setting.msubValues[0] : @"nul",
- [setting.msubValues[1] length] ? setting.msubValues[1] : @"nul",
- [setting.msubValues[2] length] ? setting.msubValues[2] : @"nul"];
+ [setting->value length] ? setting->value : @"nul",
+ [setting->button_bind length] ? setting->button_bind : @"nul",
+ [setting->axis_bind length] ? setting->axis_bind : @"nul"];
+ else if(setting->type == EnumerationSetting)
+ cell.detailTextLabel.text = setting.labelForEnumerationValue;
+ else
+ cell.detailTextLabel.text = setting->value;
return cell;
}
@@ -606,20 +743,20 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
_value = setting;
_view = table;
- _mainSection = _value.haveNoneOption ? 1 : 0;
+ _mainSection = _value->haveNoneOption ? 1 : 0;
- [self setTitle: _value.label];
+ [self setTitle: _value->label];
return self;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView
{
- return _value.haveNoneOption ? 2 : 1;
+ return _value->haveNoneOption ? 2 : 1;
}
- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section
{
- return (section == _mainSection) ? _value.subValues.count : 1;
+ return (section == _mainSection) ? _value.enumerationCount : 1;
}
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
@@ -627,14 +764,17 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
UITableViewCell* cell = [self.tableView dequeueReusableCellWithIdentifier:@"option"];
cell = cell ? cell : [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"option"];
- cell.textLabel.text = (indexPath.section == _mainSection) ? _value.subValues[indexPath.row] : @"None";
+ if (indexPath.section == _mainSection)
+ cell.textLabel.text = [_value labelForEnumerationIndex:indexPath.row];
+ else
+ cell.textLabel.text = @"None";
return cell;
}
- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
- _value.value = (indexPath.section == _mainSection) ? _value.subValues[indexPath.row] : @"";
+ [_value setValue: (indexPath.section == _mainSection) ? [_value valueForEnumerationIndex:indexPath.row] : @""];
[_view reloadData];
[[RetroArch_iOS get] popViewControllerAnimated:YES];
@@ -661,7 +801,7 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
_me = self;
_alert = [[UIAlertView alloc] initWithTitle:@"RetroArch"
- message:_value.label
+ message:_value->label
delegate:self
cancelButtonTitle:@"Cancel"
otherButtonTitles:@"Clear Keyboard", @"Clear Joystick", @"Clear Axis", nil];
@@ -689,108 +829,29 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
- (void)alertView:(UIAlertView*)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex
{
if (buttonIndex == _alert.firstOtherButtonIndex)
- _value.msubValues[0] = @"nul";
+ _value->value = @"nul";
else if(buttonIndex == _alert.firstOtherButtonIndex + 1)
- _value.msubValues[1] = @"nul";
+ _value->button_bind = @"nul";
else if(buttonIndex == _alert.firstOtherButtonIndex + 2)
- _value.msubValues[2] = @"nul";
+ _value->axis_bind = @"nul";
[self finish];
}
- (void)checkInput
{
- // Keyboard
- static const struct
- {
- const char* const keyname;
- const uint32_t hid_id;
- } ios_key_name_map[] = {
- { "left", KEY_Left }, { "right", KEY_Right },
- { "up", KEY_Up }, { "down", KEY_Down },
- { "enter", KEY_Enter }, { "kp_enter", KP_Enter },
- { "space", KEY_Space }, { "tab", KEY_Tab },
- { "shift", KEY_LeftShift }, { "rshift", KEY_RightShift },
- { "ctrl", KEY_LeftControl }, { "alt", KEY_LeftAlt },
- { "escape", KEY_Escape }, { "backspace", KEY_DeleteForward },
- { "backquote", KEY_Grave }, { "pause", KEY_Pause },
+ int32_t value = 0;
- { "f1", KEY_F1 }, { "f2", KEY_F2 },
- { "f3", KEY_F3 }, { "f4", KEY_F4 },
- { "f5", KEY_F5 }, { "f6", KEY_F6 },
- { "f7", KEY_F7 }, { "f8", KEY_F8 },
- { "f9", KEY_F9 }, { "f10", KEY_F10 },
- { "f11", KEY_F11 }, { "f12", KEY_F12 },
-
- { "num0", KEY_0 }, { "num1", KEY_1 },
- { "num2", KEY_2 }, { "num3", KEY_3 },
- { "num4", KEY_4 }, { "num5", KEY_5 },
- { "num6", KEY_6 }, { "num7", KEY_7 },
- { "num8", KEY_8 }, { "num9", KEY_9 },
+ if ((value = apple_input_find_any_key()))
+ _value->value = @(apple_keycode_hidusage_to_name(value));
+ else if ((value = apple_input_find_any_button(0)) >= 0)
+ _value->button_bind = [NSString stringWithFormat:@"%d", value];
+ else if ((value = apple_input_find_any_axis(0)))
+ _value->axis_bind = [NSString stringWithFormat:@"%s%d", (value > 0) ? "+" : "-", value - 1];
+ else
+ return;
- { "insert", KEY_Insert }, { "del", KEY_DeleteForward },
- { "home", KEY_Home }, { "end", KEY_End },
- { "pageup", KEY_PageUp }, { "pagedown", KEY_PageDown },
-
- { "add", KP_Add }, { "subtract", KP_Subtract },
- { "multiply", KP_Multiply }, { "divide", KP_Divide },
- { "keypad0", KP_0 }, { "keypad1", KP_1 },
- { "keypad2", KP_2 }, { "keypad3", KP_3 },
- { "keypad4", KP_4 }, { "keypad5", KP_5 },
- { "keypad6", KP_6 }, { "keypad7", KP_7 },
- { "keypad8", KP_8 }, { "keypad9", KP_9 },
-
- { "period", KEY_Period }, { "capslock", KEY_CapsLock },
- { "numlock", KP_NumLock }, { "print_screen", KEY_PrintScreen },
- { "scroll_lock", KEY_ScrollLock },
-
- { "a", KEY_A }, { "b", KEY_B }, { "c", KEY_C }, { "d", KEY_D },
- { "e", KEY_E }, { "f", KEY_F }, { "g", KEY_G }, { "h", KEY_H },
- { "i", KEY_I }, { "j", KEY_J }, { "k", KEY_K }, { "l", KEY_L },
- { "m", KEY_M }, { "n", KEY_N }, { "o", KEY_O }, { "p", KEY_P },
- { "q", KEY_Q }, { "r", KEY_R }, { "s", KEY_S }, { "t", KEY_T },
- { "u", KEY_U }, { "v", KEY_V }, { "w", KEY_W }, { "x", KEY_X },
- { "y", KEY_Y }, { "z", KEY_Z },
-
- { "nul", 0x00},
- };
-
- for (int i = 0; ios_key_name_map[i].hid_id; i++)
- {
- if (g_current_input_data.keys[ios_key_name_map[i].hid_id])
- {
- _value.msubValues[0] = [NSString stringWithUTF8String:ios_key_name_map[i].keyname];
- [self finish];
- return;
- }
- }
-
- // Pad Buttons
- uint32_t buttons = g_current_input_data.pad_buttons[_value.player] |
- ((_value.player == 0) ? apple_input_get_icade_buttons() : 0);
-
- for (int i = 0; buttons && i < sizeof(buttons) * 8; i++)
- {
- if (buttons & (1 << i))
- {
- _value.msubValues[1] = [NSString stringWithFormat:@"%d", i];
- [self finish];
- return;
- }
- }
-
- // Pad Axis
- for (int i = 0; i < 4; i++)
- {
- int16_t value = g_current_input_data.pad_axis[_value.player][i];
-
- if (abs(value) > 0x1000)
- {
- _value.msubValues[2] = [NSString stringWithFormat:@"%s%d", (value > 0x1000) ? "+" : "-", i];
- [self finish];
- break;
- }
- }
+ [self finish];
}
@end
diff --git a/apple/iOS/views.h b/apple/iOS/views.h
index 5b058b2ede..b2b5b887f5 100644
--- a/apple/iOS/views.h
+++ b/apple/iOS/views.h
@@ -29,6 +29,7 @@
- (id)initWithStyle:(UITableViewStyle)style;
- (id)itemForIndexPath:(NSIndexPath*)indexPath;
+- (void)reset;
@end
// browser.m
@@ -38,17 +39,22 @@
@end
// browser.m
+@protocol RADirectoryListDelegate
+- (bool)directoryList:(id)list itemWasSelected:(RADirectoryItem*)path;
+@end
+
@interface RADirectoryList : RATableViewController
@property (nonatomic, weak) RADirectoryItem *selectedItem;
-
-+ (id)directoryListAtBrowseRoot;
-+ (id)directoryListForPath:(NSString*)path;
-- (id)initWithPath:(NSString*)path;
+- (id)initWithPath:(NSString*)path delegate:(id)delegate;
@end
// browser.m
+@protocol RAModuleListDelegate
+- (bool)moduleList:(id)list itemWasSelected:(RAModuleInfo*)module;
+@end
+
@interface RAModuleList : RATableViewController
-- (id)initWithGame:(NSString*)path;
+- (id)initWithGame:(NSString*)path delegate:(id)delegate;
@end
// browser.m
diff --git a/apple/modules/bsnes_performance_libretro.info b/apple/modules/bsnes_performance_libretro.info
new file mode 100644
index 0000000000..2db7e92326
--- /dev/null
+++ b/apple/modules/bsnes_performance_libretro.info
@@ -0,0 +1,5 @@
+display_name = "SNES / Super Famicom (SNES9x Next)"
+supported_extensions = "smc|sfc"
+corename = "bsnes/higan Performance"
+manufacturer = "Nintendo"
+systemname = "Super Nintendo Entertainment System"
diff --git a/apple/modules/desmume_libretro.info b/apple/modules/desmume_libretro.info
index 9fc1326c95..7f7dcf1381 100644
--- a/apple/modules/desmume_libretro.info
+++ b/apple/modules/desmume_libretro.info
@@ -1,4 +1,4 @@
-display_name = "Nintendo DS"
+display_name = "Nintendo DS (DeSmuME)"
supported_extensions = "nds"
corename = "DeSmuME"
manufacturer = "Nintendo"
diff --git a/apple/modules/gambatte_libretro.info b/apple/modules/gambatte_libretro.info
index 123ac1c9cf..810695f3b1 100644
--- a/apple/modules/gambatte_libretro.info
+++ b/apple/modules/gambatte_libretro.info
@@ -1,4 +1,4 @@
-display_name = "Game Boy / Game Boy Color"
+display_name = "Game Boy / Game Boy Color (Gambatte)"
supported_extensions = "gb|gbc|dmg"
corename = "gambatte"
manufacturer = "Nintendo"
diff --git a/apple/modules/genesis_plus_gx_libretro.info b/apple/modules/genesis_plus_gx_libretro.info
index 17d4f786c8..4f71a60403 100644
--- a/apple/modules/genesis_plus_gx_libretro.info
+++ b/apple/modules/genesis_plus_gx_libretro.info
@@ -1,4 +1,4 @@
-display_name = "Sega (MS/GG/MD/CD)"
+display_name = "Sega MS/GG/MD/CD (Genesis Plus GX)"
supported_extensions = "md|smd|gen|sms|gg|sg|bin|cue|ios"
corename = "Genesis Plus GX"
manufacturer = "Sega"
diff --git a/apple/modules/instancingviewer_libretro.info b/apple/modules/instancingviewer_libretro.info
index 5f2a20f83b..4650def429 100644
--- a/apple/modules/instancingviewer_libretro.info
+++ b/apple/modules/instancingviewer_libretro.info
@@ -1,4 +1,4 @@
-display_name = "InstancingViewer"
+display_name = "PNG Images (InstancingViewer)"
recommended_extensions = "png"
corename = "InstancingViewer"
manufacturer = "Various"
diff --git a/apple/modules/mednafen_ngp_libretro.info b/apple/modules/mednafen_ngp_libretro.info
index 9213f37e69..40e35e45e0 100644
--- a/apple/modules/mednafen_ngp_libretro.info
+++ b/apple/modules/mednafen_ngp_libretro.info
@@ -1,4 +1,4 @@
-display_name = "Neo Geo Pocket (Color)"
+display_name = "Neo Geo Pocket/Color (Mednafen Neopop)"
supported_extensions = "ngp|ngc"
corename = "Mednafen Neopop"
manufacturer = "SNK"
diff --git a/apple/modules/mednafen_pce_fast_libretro.info b/apple/modules/mednafen_pce_fast_libretro.info
index a1b27d5ba4..9fb9b8f7a6 100644
--- a/apple/modules/mednafen_pce_fast_libretro.info
+++ b/apple/modules/mednafen_pce_fast_libretro.info
@@ -1,4 +1,4 @@
-display_name = "PC Engine/TurboGrafx-16"
+display_name = "PC Engine/TurboGrafx-16 (Mednafen PCE Fast)"
supported_extensions = "pce|sgx|cue"
corename = "Mednafen PCE Fast"
manufacturer = "NEC"
diff --git a/apple/modules/mednafen_vb_libretro.info b/apple/modules/mednafen_vb_libretro.info
index 3df42a5e14..bb7d8bd298 100644
--- a/apple/modules/mednafen_vb_libretro.info
+++ b/apple/modules/mednafen_vb_libretro.info
@@ -1,4 +1,4 @@
-display_name = "Virtual Boy"
+display_name = "Virtual Boy (Mednafen VB)"
supported_extensions = "vb|vboy|bin"
corename = "Mednafen VB"
manufacturer = "Nintendo"
diff --git a/apple/modules/mednafen_wswan_libretro.info b/apple/modules/mednafen_wswan_libretro.info
index ec1f5b9344..320e9cd941 100644
--- a/apple/modules/mednafen_wswan_libretro.info
+++ b/apple/modules/mednafen_wswan_libretro.info
@@ -1,6 +1,6 @@
-display_name = "WonderSwan (Color)"
+display_name = "WonderSwan/Color (Mednafen Cygne)"
supported_extensions = "ws|wsc"
corename = "Mednafen WonderSwan"
manufacturer = "Bandai"
-systemname = "WonderSwan (Color)"
+systemname = "WonderSwan/Color"
diff --git a/apple/modules/modelviewer_libretro.info b/apple/modules/modelviewer_libretro.info
index f6bba3967b..87fdf0fdf3 100644
--- a/apple/modules/modelviewer_libretro.info
+++ b/apple/modules/modelviewer_libretro.info
@@ -1,4 +1,4 @@
-display_name = "Modelviewer"
+display_name = "3D Models (Modelviewer)"
recommended_extensions = "obj"
corename = "Modelviewer"
manufacturer = "Various"
diff --git a/apple/modules/nxengine_libretro.info b/apple/modules/nxengine_libretro.info
index 81ac6073fd..8ec2d1b466 100644
--- a/apple/modules/nxengine_libretro.info
+++ b/apple/modules/nxengine_libretro.info
@@ -1,3 +1,3 @@
-display_name = "NXEngine (Cave Story)"
+display_name = "Cave Story (NXEngine)"
supported_extensions = "exe"
corename = "NXEngine"
diff --git a/apple/modules/picodrive_libretro.info b/apple/modules/picodrive_libretro.info
index eeea21589b..0784a12369 100644
--- a/apple/modules/picodrive_libretro.info
+++ b/apple/modules/picodrive_libretro.info
@@ -1,4 +1,4 @@
-display_name = "Sega (MS/GG/MD/CD/32X)"
+display_name = "Sega MS/GG/MD/CD/32X (Picodrive)"
supported_extensions = "md|smd|gen|sms|gg|sg|bin|cue|ios|32x"
corename = "Picodrive"
manufacturer = "Sega"
diff --git a/apple/modules/prboom_libretro.info b/apple/modules/prboom_libretro.info
index c1a416515a..f21bb605b3 100644
--- a/apple/modules/prboom_libretro.info
+++ b/apple/modules/prboom_libretro.info
@@ -1,3 +1,3 @@
-display_name = "PrBoom (DOOM)"
+display_name = "Doom (PrBoom)"
supported_extensions = "wad|iwad"
corename = "prboom"
diff --git a/apple/modules/scenewalker_libretro.info b/apple/modules/scenewalker_libretro.info
index 3cc5318f43..6edf3d7af3 100644
--- a/apple/modules/scenewalker_libretro.info
+++ b/apple/modules/scenewalker_libretro.info
@@ -1,4 +1,4 @@
-display_name = "SceneWalker"
+display_name = "3D Models (SceneWalker)"
recommended_extensions = "obj"
corename = "SceneWalker"
manufacturer = "Various"
diff --git a/apple/modules/stella_libretro.info b/apple/modules/stella_libretro.info
index a45de89830..0abb91f63a 100644
--- a/apple/modules/stella_libretro.info
+++ b/apple/modules/stella_libretro.info
@@ -1,4 +1,4 @@
-display_name = "Atari 2600"
+display_name = "Atari 2600 (Stella)"
supported_extensions = "a26|bin"
corename = "Stella"
manufacturer = "Atari"
diff --git a/apple/modules/tyrquake_libretro.info b/apple/modules/tyrquake_libretro.info
index a12b75da38..a1ca2f94e9 100644
--- a/apple/modules/tyrquake_libretro.info
+++ b/apple/modules/tyrquake_libretro.info
@@ -1,3 +1,3 @@
-display_name = "TyrQuake"
+display_name = "Quake 1 (TyrQuake)"
supported_extensions = "pak"
corename = "prboom"
diff --git a/apple/script/build b/apple/script/build
index e65f85a422..15d48e7060 100755
--- a/apple/script/build
+++ b/apple/script/build
@@ -23,7 +23,7 @@ if [ -z "$NOCODESIGN" ] ; then
xcrun -sdk iphoneos PackageApplication "$BUILD_PATH/RetroArch.app" -o "$BUILD_PATH/RetroArch.ipa" --sign "$CODE_SIGN_IDENTITY" --embed "$BUILD_PATH/RetroArch.app/embedded.mobileprovision"
else
- xcodebuild -verbose -sdk iphoneos -configuration Release
+ xcodebuild -verbose -sdk iphoneos -configuration Release -project $PROJECT_NAME
echo "Building for Jailbroken system"
fi
diff --git a/audio/coreaudio.c b/audio/coreaudio.c
index b396e6a1e3..4d71eb4b8a 100644
--- a/audio/coreaudio.c
+++ b/audio/coreaudio.c
@@ -22,6 +22,10 @@
#include "../boolean.h"
#include
+#ifdef OSX
+#include
+#endif
+
#include
#include
#include
@@ -93,6 +97,48 @@ static OSStatus audio_write_cb(void *userdata, AudioUnitRenderActionFlags *actio
return noErr;
}
+#ifdef OSX
+static void choose_output_device(coreaudio_t *dev, const char* device)
+{
+ AudioObjectPropertyAddress propaddr =
+ {
+ kAudioHardwarePropertyDevices,
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster
+ };
+
+ UInt32 size = 0;
+
+ if (AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propaddr, 0, 0, &size) != noErr)
+ return;
+
+ UInt32 deviceCount = size / sizeof(AudioDeviceID);
+ AudioDeviceID *devices = malloc(size);
+
+ if (!devices || AudioObjectGetPropertyData(kAudioObjectSystemObject, &propaddr, 0, 0, &size, devices) != noErr)
+ goto done;
+
+ propaddr.mScope = kAudioDevicePropertyScopeOutput;
+ propaddr.mSelector = kAudioDevicePropertyDeviceName;
+ size = 1024;
+
+ for (unsigned i = 0; i < deviceCount; i ++)
+ {
+ char device_name[1024];
+ device_name[0] = 0;
+
+ if (AudioObjectGetPropertyData(devices[i], &propaddr, 0, 0, &size, device_name) == noErr && strcmp(device_name, device) == 0)
+ {
+ AudioUnitSetProperty(dev->dev, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &devices[i], sizeof(AudioDeviceID));
+ goto done;
+ }
+ }
+
+done:
+ free(devices);
+}
+#endif
+
static void *coreaudio_init(const char *device, unsigned rate, unsigned latency)
{
(void)device;
@@ -121,6 +167,11 @@ static void *coreaudio_init(const char *device, unsigned rate, unsigned latency)
if (AudioComponentInstanceNew(comp, &dev->dev) != noErr)
goto error;
+#ifdef OSX
+ if (device)
+ choose_output_device(dev, device);
+#endif
+
dev->dev_alive = true;
// Set audio format
diff --git a/audio/opensl.c b/audio/opensl.c
index 068e42a7a2..beffc5456b 100644
--- a/audio/opensl.c
+++ b/audio/opensl.c
@@ -115,6 +115,8 @@ static void *sl_init(const char *device, unsigned rate, unsigned latency)
if (!sl)
goto error;
+ RARCH_LOG("[SLES]: Requested audio latency: %d ms.", latency);
+
GOTO_IF_FAIL(slCreateEngine(&sl->engine_object, 0, NULL, 0, NULL, NULL));
GOTO_IF_FAIL(SLObjectItf_Realize(sl->engine_object, SL_BOOLEAN_FALSE));
GOTO_IF_FAIL(SLObjectItf_GetInterface(sl->engine_object, SL_IID_ENGINE, &sl->engine));
@@ -122,7 +124,11 @@ static void *sl_init(const char *device, unsigned rate, unsigned latency)
GOTO_IF_FAIL(SLEngineItf_CreateOutputMix(sl->engine, &sl->output_mix, 0, NULL, NULL));
GOTO_IF_FAIL(SLObjectItf_Realize(sl->output_mix, SL_BOOLEAN_FALSE));
- sl->buf_size = next_pow2(32 * latency);
+ if (g_settings.audio.block_frames)
+ sl->buf_size = g_settings.audio.block_frames * 4;
+ else
+ sl->buf_size = next_pow2(32 * latency);
+
sl->buf_count = (latency * 4 * out_rate + 500) / 1000;
sl->buf_count = (sl->buf_count + sl->buf_size / 2) / sl->buf_size;
@@ -137,7 +143,7 @@ static void *sl_init(const char *device, unsigned rate, unsigned latency)
for (unsigned i = 0; i < sl->buf_count; i++)
sl->buffer[i] = sl->buffer_chunk + i * sl->buf_size;
- RARCH_LOG("[SLES] : Setting audio latency: Block size = %u, Blocks = %u, Total = %u ...\n",
+ RARCH_LOG("[SLES]: Setting audio latency: Block size = %u, Blocks = %u, Total = %u ...\n",
sl->buf_size, sl->buf_count, sl->buf_size * sl->buf_count);
fmt_pcm.formatType = SL_DATAFORMAT_PCM;
diff --git a/audio/rwebaudio.c b/audio/rwebaudio.c
new file mode 100644
index 0000000000..7139a88de4
--- /dev/null
+++ b/audio/rwebaudio.c
@@ -0,0 +1,90 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2010-2013 - Michael Lelli
+ *
+ * RetroArch is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with RetroArch.
+ * If not, see .
+ */
+
+#include "../driver.h"
+#include "../general.h"
+
+#include "../emscripten/RWebAudio.h"
+
+static void ra_free(void *data)
+{
+ RWebAudioFree();
+}
+
+static void *ra_init(const char *device, unsigned rate, unsigned latency)
+{
+ (void)device;
+ (void)rate;
+ void *data = RWebAudioInit(latency);
+ if (data)
+ g_settings.audio.out_rate = RWebAudioSampleRate();
+ return data;
+}
+
+static ssize_t ra_write(void *data, const void *buf, size_t size)
+{
+ (void)data;
+ return RWebAudioWrite(buf, size);
+}
+
+static bool ra_stop(void *data)
+{
+ (void)data;
+ return RWebAudioStop();
+}
+
+static void ra_set_nonblock_state(void *data, bool state)
+{
+ (void)data;
+ RWebAudioSetNonblockState(state);
+}
+
+static bool ra_start(void *data)
+{
+ (void)data;
+ return RWebAudioStart();
+}
+
+static bool ra_use_float(void *data)
+{
+ (void)data;
+ return true;
+}
+
+static size_t ra_write_avail(void *data)
+{
+ (void)data;
+ return RWebAudioWriteAvail();
+}
+
+static size_t ra_buffer_size(void *data)
+{
+ (void)data;
+ return RWebAudioBufferSize();
+}
+
+const audio_driver_t audio_rwebaudio = {
+ ra_init,
+ ra_write,
+ ra_stop,
+ ra_start,
+ ra_set_nonblock_state,
+ ra_free,
+ ra_use_float,
+ "rwebaudio",
+ ra_write_avail,
+ ra_buffer_size,
+};
+
diff --git a/audio/thread_wrapper.c b/audio/thread_wrapper.c
index 0c762aa15f..f507ff89ee 100644
--- a/audio/thread_wrapper.c
+++ b/audio/thread_wrapper.c
@@ -57,7 +57,7 @@ static void audio_thread_loop(void *data)
}
slock_unlock(thr->lock);
- g_extern.system.audio_callback();
+ g_extern.system.audio_callback.callback();
}
}
@@ -98,12 +98,14 @@ static bool audio_thread_stop(void *data)
{
audio_thread_t *thr = (audio_thread_t*)data;
audio_thread_block(thr);
+ g_extern.system.audio_callback.set_state(false);
return true;
}
static bool audio_thread_start(void *data)
{
audio_thread_t *thr = (audio_thread_t*)data;
+ g_extern.system.audio_callback.set_state(true);
audio_thread_unblock(thr);
return true;
}
diff --git a/blackberry-qnx/qnx_input.c b/blackberry-qnx/qnx_input.c
index d6f6985886..52957a6222 100644
--- a/blackberry-qnx/qnx_input.c
+++ b/blackberry-qnx/qnx_input.c
@@ -627,7 +627,7 @@ static int16_t qnx_input_state(void *data, const struct retro_keybind **retro_ke
static bool qnx_input_key_pressed(void *data, int key)
{
- return ((g_extern.lifecycle_state | driver.overlay_state ) & (1ULL << key));
+ return ((g_extern.lifecycle_state | driver.overlay_state.buttons ) & (1ULL << key));
}
static void qnx_input_free_input(void *data)
diff --git a/conf/config_file.c b/conf/config_file.c
index 8fcbd92ceb..05327d6cc3 100644
--- a/conf/config_file.c
+++ b/conf/config_file.c
@@ -355,6 +355,54 @@ static config_file_t *config_file_new_internal(const char *path, unsigned depth)
return conf;
}
+config_file_t *config_file_new_from_string(const char *from_string)
+{
+ struct config_file *conf = (struct config_file*)calloc(1, sizeof(*conf));
+ if (!conf)
+ return NULL;
+
+ if (!from_string)
+ return conf;
+
+ conf->path = NULL;
+ conf->include_depth = 0;
+
+ struct string_list *lines = string_split(from_string, "\n");
+ if (!lines)
+ return conf;
+
+ for (size_t i = 0; i < lines->size; i++)
+ {
+ struct config_entry_list *list = (struct config_entry_list*)calloc(1, sizeof(*list));
+
+ char* line = lines->elems[i].data;
+
+ if (line)
+ {
+ if (parse_line(conf, list, line))
+ {
+ if (conf->entries)
+ {
+ conf->tail->next = list;
+ conf->tail = list;
+ }
+ else
+ {
+ conf->entries = list;
+ conf->tail = list;
+ }
+ }
+ }
+
+ if (list != conf->tail)
+ free(list);
+ }
+
+ string_list_free(lines);
+
+ return conf;
+}
+
config_file_t *config_file_new(const char *path)
{
return config_file_new_internal(path, 0);
diff --git a/conf/config_file.h b/conf/config_file.h
index 8ae7554181..ad366e84ca 100644
--- a/conf/config_file.h
+++ b/conf/config_file.h
@@ -41,6 +41,8 @@ typedef struct config_file config_file_t;
// Loads a config file. Returns NULL if file doesn't exist.
// NULL path will create an empty config file.
config_file_t *config_file_new(const char *path);
+// Load a config file from a string.
+config_file_t *config_file_new_from_string(const char *from_string);
// Frees config file.
void config_file_free(config_file_t *conf);
diff --git a/config.def.h b/config.def.h
index a677cc2778..da09d29909 100644
--- a/config.def.h
+++ b/config.def.h
@@ -63,6 +63,7 @@ enum
AUDIO_PS3,
AUDIO_XENON360,
AUDIO_WII,
+ AUDIO_RWEBAUDIO,
AUDIO_NULL,
INPUT_ANDROID,
@@ -77,6 +78,7 @@ enum
INPUT_LINUXRAW,
INPUT_APPLE,
INPUT_QNX,
+ INPUT_RWEBINPUT,
INPUT_NULL
};
@@ -130,6 +132,8 @@ enum
#define AUDIO_DEFAULT_DRIVER AUDIO_SL
#elif defined(HAVE_DSOUND)
#define AUDIO_DEFAULT_DRIVER AUDIO_DSOUND
+#elif defined(EMSCRIPTEN)
+#define AUDIO_DEFAULT_DRIVER AUDIO_RWEBAUDIO
#elif defined(HAVE_SDL)
#define AUDIO_DEFAULT_DRIVER AUDIO_SDL
#elif defined(HAVE_XAUDIO)
@@ -152,6 +156,8 @@ enum
#define INPUT_DEFAULT_DRIVER INPUT_ANDROID
#elif defined(_WIN32)
#define INPUT_DEFAULT_DRIVER INPUT_DINPUT
+#elif defined(EMSCRIPTEN)
+#define INPUT_DEFAULT_DRIVER INPUT_RWEBINPUT
#elif defined(HAVE_SDL)
#define INPUT_DEFAULT_DRIVER INPUT_SDL
#elif defined(__CELLOS_LV2__)
@@ -215,6 +221,14 @@ static const bool hard_sync = false;
// 2: Etc ...
static const unsigned hard_sync_frames = 0;
+// Inserts a black frame inbetween frames.
+// Useful for 120 Hz monitors who want to play 60 Hz material with eliminated ghosting. video_refresh_rate should still be configured as if it is a 60 Hz monitor (divide refresh rate by 2).
+static bool black_frame_insertion = false;
+
+// Uses a custom swap interval for VSync.
+// Set this to effectively halve monitor refresh rate.
+static unsigned swap_interval = 1;
+
// Threaded video. Will possibly increase performance significantly at cost of worse synchronization and latency.
static const bool video_threaded = false;
diff --git a/dist-scripts/retroarch-CHANGELOG.txt b/dist-scripts/retroarch-CHANGELOG.txt
index 4dcf4951d9..1d15c41024 100644
--- a/dist-scripts/retroarch-CHANGELOG.txt
+++ b/dist-scripts/retroarch-CHANGELOG.txt
@@ -1,3 +1,61 @@
+------------------------------------------------------------------------------
+v0.9.9.6
+------------------------------------------------------------------------------
+* [VBA Next] Fixes serious regressions - most evident in Golden Sun games -
+battle screens etc.
+* [VBA Next] Add a core option to change the control button layout from (left
+to right) B to A to (left to right) A to B.
+* [Android] Added Load Game History to Android Java UI
+* [Android] Will show a progressbar dialog during asset extraction so that the
+user knows what is happening.
+
+------------------------------------------------------------------------------
+v0.9.9.5
+------------------------------------------------------------------------------
+* [Android] Input autodetection fixes -
+ - DualShock3 pad controls fixed
+* [Android] It should now be possible to map D-pad to analog on several gamepads, such as:
+ - Xbox 360
+ - PlayStation3
+ - Shield
+* [Android] Threaded video is now the default due to positive user feedback. Purists and accuracy
+people can still go for static syncing for best results - although for PCSX ReARMed threaded
+video is essential. With the combination of threaded video and dynamic audio rate control,
+most of the audio pops and sync issues should be a thing of the past now. Yay.
+* [Android] UI has been reorganized and made less shitty (yes, we know). Still a long
+way to go there. The entire menu should be gamepad-controllable now at least.
+* [Android] Shaders that were broken on Nexus 7/4/10 etc. should now work
+* [Android] Added some additional autodetection rules:
+ - Ouya: Input overlays are disabled by default
+* [Android] Added high-latency audio option for crappy/old Android devices that
+can't handle the lower-latency audio that is the default since 0.9.9.4. This should
+give you the same performance as 0.9.9.3 (r17). Turn this on if you get bad sound/performance
+(and it's not your device simply being slow). This might also apply for some of the newer
+devices - perhaps OpenSL driver has not been updated/optimized there.
+* [Android] Added a TV mode. This will launch you straight into RGUI mode. This mode
+is identical to what you get from the Wii and PC ports of RetroArch at startup. First
+you select a core, then you select a game to go with it.
+* [SNES9x] Fixes by Alcaro to libretro port
+* [SNES9x Next] Fixes savestates from not being able to be loaded.
+* (LIBRETRO) Added bsnes/higan performance core [v0.92] (Android).
+ - bsnes/higan performance core will run all non-coprocessor games at fullspeed on an
+ nVidia Shield.
+ - Co-processor games (SuperFX/SA-1/DSP/Cx4/SA1) will run between ~40fps and 55-57fps
+ on an nVidia Shield - depending on the specific co-processor. Note - you will need
+ BIOS files for these games - see byuu boards for information on them.
+* [Mednafen NGP] Fixes input issues in a number of games, such as:
+ - Card Fighters games
+ - Etc.
+* [Picodrive] Updates/32X compatibility/accuracy improvements
+* [NEStopia] Updated to 1.46 WIP - added ability to load NstDatabase.xml, fixes Vs. System games
+and Startropics 1/2
+* [iOS] Only player 1 gets default keyboard bindings
+* [iOS] Fixes PS3 gamepad bindings in RGUI
+* [iOS] Fixes iCade button mappings
+* [iOS] UI additions - Refresh / New Folder / Move options.
+* [iOS] Some lifecycle management fixes - should deal better now with phone calls
+received and then returning back to RA, etc.
+
------------------------------------------------------------------------------
v0.9.9.3
------------------------------------------------------------------------------
diff --git a/driver.c b/driver.c
index b9795818af..5397b3629b 100644
--- a/driver.c
+++ b/driver.c
@@ -84,6 +84,9 @@ static const audio_driver_t *audio_drivers[] = {
#ifdef GEKKO
&audio_gx,
#endif
+#ifdef EMSCRIPTEN
+ &audio_rwebaudio,
+#endif
#ifdef HAVE_NULLAUDIO
&audio_null,
#endif
@@ -165,6 +168,9 @@ static const input_driver_t *input_drivers[] = {
#ifdef __BLACKBERRY_QNX__
&input_qnx,
#endif
+#ifdef EMSCRIPTEN
+ &input_rwebinput,
+#endif
#ifdef HAVE_NULLINPUT
&input_null,
#endif
@@ -506,7 +512,7 @@ void init_audio(void)
#ifdef HAVE_THREADS
find_audio_driver();
- if (g_extern.system.audio_callback)
+ if (g_extern.system.audio_callback.callback)
{
RARCH_LOG("Starting threaded audio driver ...\n");
if (!rarch_threaded_audio_init(&driver.audio, &driver.audio_data,
@@ -560,7 +566,7 @@ void init_audio(void)
rarch_assert(g_extern.audio_data.outsamples = (float*)malloc(outsamples_max * sizeof(float)));
g_extern.audio_data.rate_control = false;
- if (!g_extern.system.audio_callback && g_extern.audio_active && g_settings.audio.rate_control)
+ if (!g_extern.system.audio_callback.callback && g_extern.audio_active && g_settings.audio.rate_control)
{
if (driver.audio->buffer_size && driver.audio->write_avail)
{
@@ -580,7 +586,7 @@ void init_audio(void)
g_extern.measure_data.buffer_free_samples_count = 0;
- if (g_extern.audio_active && !g_extern.audio_data.mute && g_extern.system.audio_callback) // Threaded driver is initially stopped.
+ if (g_extern.audio_active && !g_extern.audio_data.mute && g_extern.system.audio_callback.callback) // Threaded driver is initially stopped.
audio_start_func();
}
@@ -1058,7 +1064,7 @@ void uninit_video_input(void)
{
input_overlay_free(driver.overlay);
driver.overlay = NULL;
- driver.overlay_state = 0;
+ memset(&driver.overlay_state, 0, sizeof(driver.overlay_state));
}
#endif
diff --git a/driver.h b/driver.h
index bc4cdd7d1a..5a30c74d8c 100644
--- a/driver.h
+++ b/driver.h
@@ -19,7 +19,7 @@
#include
#include "boolean.h"
-#include "libretro.h"
+#include "libretro_private.h"
#include
#include
#include "msvc/msvc_compat.h"
@@ -462,7 +462,7 @@ typedef struct driver
#ifdef HAVE_OVERLAY
input_overlay_t *overlay;
- uint64_t overlay_state;
+ input_overlay_state_t overlay_state;
#endif
// Interface for "poking".
@@ -511,6 +511,7 @@ extern const audio_driver_t audio_coreaudio;
extern const audio_driver_t audio_xenon360;
extern const audio_driver_t audio_ps3;
extern const audio_driver_t audio_gx;
+extern const audio_driver_t audio_rwebaudio;
extern const audio_driver_t audio_null;
extern const video_driver_t video_gl;
extern const video_driver_t video_psp1;
@@ -536,6 +537,7 @@ extern const input_driver_t input_xinput;
extern const input_driver_t input_linuxraw;
extern const input_driver_t input_apple;
extern const input_driver_t input_qnx;
+extern const input_driver_t input_rwebinput;
extern const input_driver_t input_null;
#include "driver_funcs.h"
diff --git a/driver_funcs.h b/driver_funcs.h
index 69319e2104..56237a9cd6 100644
--- a/driver_funcs.h
+++ b/driver_funcs.h
@@ -56,7 +56,7 @@ static inline bool input_key_pressed_func(int key)
bool ret = driver.input->key_pressed(driver.input_data, key);
#ifdef HAVE_OVERLAY
- ret |= driver.overlay_state & (UINT64_C(1) << key);
+ ret |= driver.overlay_state.buttons & (UINT64_C(1) << key);
#endif
#ifdef HAVE_COMMAND
diff --git a/dynamic.c b/dynamic.c
index 401b1f4e46..d1b356e067 100644
--- a/dynamic.c
+++ b/dynamic.c
@@ -30,7 +30,7 @@
#endif
#include "boolean.h"
-#include "libretro.h"
+#include "libretro_private.h"
#include "dynamic_dummy.h"
#ifdef NEED_DYNAMIC
@@ -93,8 +93,6 @@ unsigned (*pretro_get_region)(void);
void *(*pretro_get_memory_data)(unsigned);
size_t (*pretro_get_memory_size)(unsigned);
-static bool environment_cb(unsigned cmd, void *data);
-
#ifdef HAVE_DYNAMIC
#if defined(__APPLE__)
#define DYNAMIC_EXT "dylib"
@@ -397,7 +395,7 @@ void init_libretro_sym(bool dummy)
load_symbols(dummy);
- pretro_set_environment(environment_cb);
+ pretro_set_environment(rarch_environment_cb);
}
void uninit_libretro_sym(void)
@@ -471,7 +469,7 @@ void dylib_close(dylib_t lib)
}
#endif
-static bool environment_cb(unsigned cmd, void *data)
+bool rarch_environment_cb(unsigned cmd, void *data)
{
switch (cmd)
{
@@ -739,7 +737,7 @@ static bool environment_cb(unsigned cmd, void *data)
return false;
#endif
- g_extern.system.audio_callback = info->callback;
+ g_extern.system.audio_callback = *info;
break;
}
#endif
@@ -758,6 +756,41 @@ static bool environment_cb(unsigned cmd, void *data)
break;
}
+ case RETRO_ENVIRONMENT_SET_LIBRETRO_PATH:
+ RARCH_LOG("Environ (Private) SET_LIBRETRO_PATH.\n");
+
+ if (path_file_exists((const char*)data))
+ strlcpy(g_settings.libretro, (const char*)data, sizeof(g_settings.libretro));
+ else
+ return false;
+ break;
+
+ case RETRO_ENVIRONMENT_EXEC:
+ case RETRO_ENVIRONMENT_EXEC_ESCAPE:
+
+ if (data)
+ strlcpy(g_extern.fullpath, (const char*)data, sizeof(g_extern.fullpath));
+ else
+ *g_extern.fullpath = '\0';
+
+#if !defined( HAVE_DYNAMIC) && defined(RARCH_CONSOLE)
+ g_extern.lifecycle_mode_state &= ~(1ULL << MODE_GAME);
+ g_extern.lifecycle_mode_state |= (1ULL << MODE_EXITSPAWN);
+ g_extern.lifecycle_mode_state |= (1ULL << MODE_EXITSPAWN_START_GAME);
+#elif defined(HAVE_DYNAMIC)
+ g_extern.lifecycle_mode_state |= (1ULL << MODE_LOAD_GAME);
+#endif
+
+ if (cmd == RETRO_ENVIRONMENT_EXEC_ESCAPE)
+ {
+ RARCH_LOG("Environ (Private) EXEC_ESCAPE.\n");
+ g_extern.exec = true;
+ }
+ else
+ RARCH_LOG("Environ (Private) EXEC.\n");
+
+ break;
+
default:
RARCH_LOG("Environ UNSUPPORTED (#%u).\n", cmd);
return false;
diff --git a/dynamic.h b/dynamic.h
index 6efa2722fb..198f81e39e 100644
--- a/dynamic.h
+++ b/dynamic.h
@@ -101,6 +101,8 @@ extern unsigned (*pretro_get_region)(void);
extern void *(*pretro_get_memory_data)(unsigned);
extern size_t (*pretro_get_memory_size)(unsigned);
+extern bool rarch_environment_cb(unsigned cmd, void *data);
+
#ifdef __cplusplus
}
#endif
diff --git a/emscripten/RWebAudio.h b/emscripten/RWebAudio.h
new file mode 100644
index 0000000000..6911753923
--- /dev/null
+++ b/emscripten/RWebAudio.h
@@ -0,0 +1,28 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2010-2013 - Michael Lelli
+ *
+ * RetroArch is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with RetroArch.
+ * If not, see .
+ */
+
+#include
+#include
+#include
+
+unsigned RWebAudioSampleRate(void);
+void *RWebAudioInit(unsigned latency);
+ssize_t RWebAudioWrite(const void *buf, size_t size);
+bool RWebAudioStop(void);
+bool RWebAudioStart(void);
+void RWebAudioSetNonblockState(bool state);
+void RWebAudioFree(void);
+size_t RWebAudioWriteAvail(void);
+size_t RWebAudioBufferSize(void);
diff --git a/emscripten/RWebInput.h b/emscripten/RWebInput.h
new file mode 100644
index 0000000000..103cc7a0cd
--- /dev/null
+++ b/emscripten/RWebInput.h
@@ -0,0 +1,29 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2010-2013 - Michael Lelli
+ *
+ * RetroArch is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with RetroArch.
+ * If not, see .
+ */
+
+#include
+
+typedef struct rwebinput_state
+{
+ char keys[32];
+ int mouse_x;
+ int mouse_y;
+ char mouse_l;
+ char mouse_r;
+} rwebinput_state_t;
+
+int RWebInputInit(void);
+rwebinput_state_t *RWebInputPoll(int context);
+void RWebInputDestroy(int context);
diff --git a/emscripten/library_rwebaudio.js b/emscripten/library_rwebaudio.js
new file mode 100644
index 0000000000..4e7594ec45
--- /dev/null
+++ b/emscripten/library_rwebaudio.js
@@ -0,0 +1,166 @@
+//"use strict";
+
+var LibraryRWebAudio = {
+ $RA__deps: ['$Browser', 'usleep'],
+ $RA: {
+ BUFFER_SIZE: 256,
+
+ context: null,
+ buffers: [],
+ numBuffers: 0,
+ bufIndex: 0,
+ bufOffset: 0,
+ startTime: 0,
+ nonblock: false,
+ currentTimeWorkaround: false,
+
+ setStartTime: function() {
+ if (RA.context.currentTime) {
+ RA.startTime = window['performance']['now']() - RA.context.currentTime * 1000;
+ var time1 = RA.context.currentTime;
+ _usleep(50);
+ if (time1 === RA.context.currentTime) {
+ RA.currentTimeWorkaround = true;
+ if (RA.startTime === 0) throw 'startTime is 0';
+ }
+ Module["resumeMainLoop"]();
+ } else window['setTimeout'](RA.setStartTime, 0);
+ },
+
+ getCurrentPerfTime: function() {
+ if (!RA.currentTimeWorkaround) return RA.context.currentTime;
+ else if (RA.startTime) return (window['performance']['now']() - RA.startTime) / 1000;
+ else throw 'getCurrentPerfTime() called before start time set';
+ },
+
+ process: function(queueBuffers) {
+ var currentTime = RA.getCurrentPerfTime();
+ for (var i = 0; i < RA.bufIndex; i++) {
+ if (RA.buffers[i].endTime < currentTime) {
+ var buf = RA.buffers.splice(i, 1);
+ RA.buffers[RA.numBuffers - 1] = buf[0];
+ i--;
+ RA.bufIndex--;
+ }
+ }
+ },
+
+ fillBuffer: function(buf, samples) {
+ var count = 0;
+ var leftBuffer = RA.buffers[RA.bufIndex].getChannelData(0);
+ var rightBuffer = RA.buffers[RA.bufIndex].getChannelData(1);
+ while (samples && RA.bufOffset !== RA.BUFFER_SIZE) {
+ leftBuffer[RA.bufOffset] = {{{ makeGetValue('buf', 'count * 8', 'float') }}};
+ rightBuffer[RA.bufOffset] = {{{ makeGetValue('buf', 'count * 8 + 4', 'float') }}};
+ RA.bufOffset++;
+ count++;
+ samples--;
+ }
+
+ return count;
+ },
+
+ queueAudio: function() {
+ var index = RA.bufIndex;
+
+ var startTime;
+ if (RA.bufIndex) startTime = RA.buffers[RA.bufIndex - 1].endTime;
+ else startTime = RA.context.currentTime;
+ RA.buffers[index].endTime = startTime + RA.buffers[index].duration;
+
+ var bufferSource = RA.context.createBufferSource();
+ bufferSource.buffer = RA.buffers[index];
+ bufferSource.connect(RA.context.destination);
+ bufferSource.start(startTime);
+
+ RA.bufIndex++;
+ RA.bufOffset = 0;
+ },
+
+ block: function() {
+ do {
+ RA.process();
+ } while (RA.bufIndex === RA.numBuffers - 1);
+ }
+ },
+
+ RWebAudioInit: function(latency) {
+ var ac = window['AudioContext'] || window['webkitAudioContext'];
+
+ if (!ac) return 0;
+
+ RA.context = new ac();
+
+ RA.numBuffers = ((latency * RA.context.sampleRate) / (1000 * RA.BUFFER_SIZE))|0;
+ if (RA.numBuffers < 2) RA.numBuffers = 2;
+
+ for (var i = 0; i < RA.numBuffers; i++) RA.buffers[i] = RA.context.createBuffer(2, RA.BUFFER_SIZE, RA.context.sampleRate);
+
+ RA.nonblock = false;
+ RA.startTime = 0;
+ // chrome hack to get currentTime running
+ RA.context.createGain();
+ window['setTimeout'](RA.setStartTime, 0);
+ Module["pauseMainLoop"]();
+ return 1;
+ },
+
+ RWebAudioSampleRate: function() {
+ return RA.context.sampleRate;
+ },
+
+ RWebAudioWrite: function (buf, size) {
+ RA.process();
+ var samples = size / 8;
+ var count = 0;
+
+ while (samples) {
+ var fill = RA.fillBuffer(buf, samples);
+ samples -= fill;
+ count += fill;
+ buf += fill * 8;
+
+ if (RA.bufOffset === RA.BUFFER_SIZE) {
+ if (RA.bufIndex === RA.numBuffers - 1) {
+ if (RA.nonblock) break;
+ else RA.block();
+ }
+ RA.queueAudio();
+ }
+ }
+
+ return count * 8;
+ },
+
+ RWebAudioStop: function() {
+ RA.bufIndex = 0;
+ RA.bufOffset = 0;
+ return true;
+ },
+
+ RWebAudioStart: function() {
+ return true;
+ },
+
+ RWebAudioSetNonblockState: function(state) {
+ RA.nonblock = state;
+ },
+
+ RWebAudioFree: function() {
+ RA.bufIndex = 0;
+ RA.bufOffset = 0;
+ return;
+ },
+
+ RWebAudioBufferSize: function() {
+ return RA.numBuffers * RA.BUFFER_SIZE + RA.BUFFER_SIZE;
+ },
+
+ RWebAudioWriteAvail: function() {
+ RA.process();
+ return ((RA.numBuffers - RA.bufIndex) * RA.BUFFER_SIZE - RA.bufOffset) * 8;
+ }
+};
+
+autoAddDeps(LibraryRWebAudio, '$RA');
+mergeInto(LibraryManager.library, LibraryRWebAudio);
diff --git a/emscripten/library_rwebinput.js b/emscripten/library_rwebinput.js
new file mode 100644
index 0000000000..7f45a747d8
--- /dev/null
+++ b/emscripten/library_rwebinput.js
@@ -0,0 +1,108 @@
+//"use strict";
+
+var LibraryRWebInput = {
+ $RI__deps: ['$Browser'],
+ $RI: {
+ temp: null,
+ contexts: [],
+
+ eventHandler: function(event) {
+ var i;
+ switch (event.type) {
+ case 'mousemove':
+ var x = event['movementX'] || event['mozMovementX'] || event['webkitMovementX'];
+ var y = event['movementY'] || event['mozMovementY'] || event['webkitMovementY'];
+ for (i = 0; i < RI.contexts.length; i++) {
+ var oldX = {{{ makeGetValue('RI.contexts[i].state', '32', 'i32') }}};
+ var oldY = {{{ makeGetValue('RI.contexts[i].state', '36', 'i32') }}};
+ x += oldX;
+ y += oldY;
+ {{{ makeSetValue('RI.contexts[i].state', '32', 'x', 'i32') }}};
+ {{{ makeSetValue('RI.contexts[i].state', '36', 'y', 'i32') }}};
+ }
+ break;
+ case 'mouseup':
+ case 'mousedown':
+ var value;
+ var offset;
+ if (event.button === 0) offset = 40;
+ else if (event.button === 2) offset = 41;
+ else break;
+ if (event.type === 'mouseup') value = 0;
+ else value = 1;
+ for (i = 0; i < RI.contexts.length; i++) {
+ {{{ makeSetValue('RI.contexts[i].state', 'offset', 'value', 'i8') }}};
+ }
+ break;
+ case 'keyup':
+ case 'keydown':
+ var key = event.keyCode;
+ var offset = key >> 3;
+ var bit = 1 << (key & 7);
+ if (offset >= 32) throw 'key code error! bad code: ' + key;
+ for (i = 0; i < RI.contexts.length; i++) {
+ var value = {{{ makeGetValue('RI.contexts[i].state', 'offset', 'i8') }}};
+ if (event.type === 'keyup') value &= ~bit;
+ else value |= bit;
+ {{{ makeSetValue('RI.contexts[i].state', 'offset', 'value', 'i8') }}};
+ }
+ event.preventDefault();
+ break;
+ case 'blur':
+ case 'visibilitychange':
+ for (i = 0; i < RI.contexts.length; i++) {
+ _memset(RI.contexts[i].state, 0, 42);
+ }
+ break;
+ }
+ }
+ },
+
+ RWebInputInit: function(latency) {
+ if (RI.contexts.length === 0) {
+ document.addEventListener('keyup', RI.eventHandler, false);
+ document.addEventListener('keydown', RI.eventHandler, false);
+ document.addEventListener('mousemove', RI.eventHandler, false);
+ document.addEventListener('mouseup', RI.eventHandler, false);
+ document.addEventListener('mousedown', RI.eventHandler, false);
+ document.addEventListener('blur', RI.eventHandler, false);
+ document.addEventListener('onvisbilitychange', RI.eventHandler, false);
+ }
+ if (RI.temp === null) RI.temp = _malloc(42);
+
+ var s = _malloc(42);
+ _memset(s, 0, 42);
+ RI.contexts.push({
+ state: s
+ });
+ return RI.contexts.length;
+ },
+
+ RWebInputPoll: function(context) {
+ context -= 1;
+ var state = RI.contexts[context].state;
+ _memcpy(RI.temp, state, 42);
+ // reset mouse movements
+ {{{ makeSetValue('RI.contexts[context].state', '32', '0', 'i32') }}};
+ {{{ makeSetValue('RI.contexts[context].state', '36', '0', 'i32') }}};
+ return RI.temp;
+ },
+
+ RWebInputDestroy: function (context) {
+ if (context === RI.contexts.length) {
+ RI.contexts.pop();
+ if (RI.contexts.length === 0) {
+ document.removeEventListener('keyup', RI.eventHandler, false);
+ document.removeEventListener('keydown', RI.eventHandler, false);
+ document.removeEventListener('mousemove', RI.eventHandler, false);
+ document.removeEventListener('mouseup', RI.eventHandler, false);
+ document.removeEventListener('mousedown', RI.eventHandler, false);
+ document.removeEventListener('blur', RI.eventHandler, false);
+ document.removeEventListener('onvisbilitychange', RI.eventHandler, false);
+ }
+ }
+ }
+};
+
+autoAddDeps(LibraryRWebInput, '$RI');
+mergeInto(LibraryManager.library, LibraryRWebInput);
diff --git a/file_ext.h b/file_ext.h
index bdfddeea3a..54bfb79cf5 100644
--- a/file_ext.h
+++ b/file_ext.h
@@ -42,6 +42,8 @@
#define EXT_EXECUTABLES "dol|DOL"
#define SALAMANDER_FILE "boot.dol"
#define DEFAULT_EXE_EXT ".dol"
+#elif defined(EMSCRIPTEN)
+#define EXT_EXECUTABLES ""
#endif
#endif
diff --git a/frontend/frontend.c b/frontend/frontend.c
index 174f1a8084..4102b07fbb 100644
--- a/frontend/frontend.c
+++ b/frontend/frontend.c
@@ -63,9 +63,7 @@ static bool libretro_install_core(const char *path_prefix,
return false;
}
- strlcpy(g_settings.libretro, new_path,
- sizeof(g_settings.libretro));
-
+ rarch_environment_cb(RETRO_ENVIRONMENT_SET_LIBRETRO_PATH, (void*)new_path);
return true;
}
@@ -124,20 +122,15 @@ void rarch_get_environment_console(void)
}
#endif
-#if defined(IOS) || defined(OSX)
-void* rarch_main(void* args)
-{
- int argc = 0;
- char *argv = NULL;
-#elif defined(HAVE_BB10)
-int rarch_main(int argc, char *argv[])
-{
- void* args = NULL;
+#if defined(IOS) || defined(OSX) || defined(HAVE_BB10)
+#define main_entry rarch_main
#else
-int main(int argc, char *argv[])
+#define main_entry main
+#endif
+
+int main_entry(int argc, char *argv[])
{
void* args = NULL;
-#endif
frontend_ctx = (frontend_ctx_driver_t*)frontend_ctx_init_first();
if (frontend_ctx && frontend_ctx->init)
@@ -151,31 +144,16 @@ int main(int argc, char *argv[])
frontend_ctx->environment_get(argc, argv, args);
#if !defined(RARCH_CONSOLE) && !defined(HAVE_BB10)
-#if defined(__APPLE__)
- struct rarch_main_wrap* argdata = (struct rarch_main_wrap*)args;
- int init_ret = rarch_main_init_wrap(argdata);
- apple_free_main_wrap(argdata);
-
- if (init_ret)
- {
- rarch_main_clear_state();
- dispatch_async_f(dispatch_get_main_queue(), (void*)1, apple_rarch_exited);
- return 0;
- }
-#else
rarch_init_msg_queue();
int init_ret;
if ((init_ret = rarch_main_init(argc, argv))) return init_ret;
#endif
-#endif
#if defined(HAVE_MENU) || defined(HAVE_BB10)
menu_init();
-#ifndef __APPLE__
if (frontend_ctx && frontend_ctx->process_args)
frontend_ctx->process_args(argc, argv, args);
-#endif
#if defined(RARCH_CONSOLE) || defined(HAVE_BB10)
g_extern.lifecycle_mode_state |= 1ULL << MODE_LOAD_GAME;
diff --git a/frontend/frontend_android.c b/frontend/frontend_android.c
index a1b26f45f2..6d578b3691 100644
--- a/frontend/frontend_android.c
+++ b/frontend/frontend_android.c
@@ -153,9 +153,11 @@ static bool android_app_start_main(struct android_app *android_app)
config_load();
menu_init();
+
ret = load_menu_game();
if (ret)
g_extern.lifecycle_mode_state |= (1ULL << MODE_GAME);
+
return ret;
}
diff --git a/frontend/frontend_context.c b/frontend/frontend_context.c
index 24fa1dd161..3072732b4c 100644
--- a/frontend/frontend_context.c
+++ b/frontend/frontend_context.c
@@ -36,11 +36,12 @@ static const frontend_ctx_driver_t *frontend_ctx_drivers[] = {
#if defined(IOS) || defined(OSX)
&frontend_ctx_apple,
#endif
+ NULL // zero length array is not valid
};
const frontend_ctx_driver_t *frontend_ctx_find_driver(const char *ident)
{
- for (unsigned i = 0; i < sizeof(frontend_ctx_drivers) / sizeof(frontend_ctx_drivers[0]); i++)
+ for (unsigned i = 0; frontend_ctx_drivers[i]; i++)
{
if (strcmp(frontend_ctx_drivers[i]->ident, ident) == 0)
return frontend_ctx_drivers[i];
@@ -51,7 +52,7 @@ const frontend_ctx_driver_t *frontend_ctx_find_driver(const char *ident)
const frontend_ctx_driver_t *frontend_ctx_init_first(void)
{
- for (unsigned i = 0; i < sizeof(frontend_ctx_drivers) / sizeof(frontend_ctx_drivers[0]); i++)
+ for (unsigned i = 0; frontend_ctx_drivers[i]; i++)
return frontend_ctx_drivers[i];
return NULL;
diff --git a/frontend/frontend_emscripten.c b/frontend/frontend_emscripten.c
new file mode 100644
index 0000000000..1941e49984
--- /dev/null
+++ b/frontend/frontend_emscripten.c
@@ -0,0 +1,147 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2010-2013 - Hans-Kristian Arntzen
+ * Copyright (C) 2011-2013 - Daniel De Matteis
+ *
+ * RetroArch is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with RetroArch.
+ * If not, see .
+ */
+
+#include
+#include "../general.h"
+#include "../conf/config_file.h"
+#include "../file.h"
+#include "../emscripten/RWebAudio.h"
+
+#ifdef HAVE_RGUI
+#include "../frontend/menu/rgui.h"
+#endif
+
+#if defined(HAVE_RGUI) || defined(HAVE_RMENU) || defined(HAVE_RMENU_XUI)
+#define HAVE_MENU
+#else
+#undef HAVE_MENU
+#endif
+
+static bool menuloop;
+
+static void endloop(void)
+{
+ g_extern.system.shutdown = false;
+ menu_free();
+
+ if (g_extern.config_save_on_exit && *g_extern.config_path)
+ config_save_file(g_extern.config_path);
+
+ if (g_extern.main_is_init)
+ rarch_main_deinit();
+
+ rarch_deinit_msg_queue();
+
+#ifdef PERF_TEST
+ rarch_perf_log();
+#endif
+
+ rarch_main_clear_state();
+
+ exit(0);
+}
+
+static void mainloop(void)
+{
+ if (g_extern.system.shutdown)
+ {
+ endloop();
+ }
+ else if (menuloop)
+ {
+ if (!menu_iterate())
+ {
+ menuloop = false;
+ driver_set_nonblock_state(driver.nonblock_state);
+
+ if (driver.audio_data && !audio_start_func())
+ {
+ RARCH_ERR("Failed to resume audio driver. Will continue without audio.\n");
+ g_extern.audio_active = false;
+ }
+
+ g_extern.lifecycle_mode_state &= ~(1ULL << MODE_MENU);
+ }
+ }
+ else if (g_extern.lifecycle_mode_state & (1ULL << MODE_LOAD_GAME))
+ {
+ load_menu_game_prepare();
+
+ // If ROM load fails, we exit RetroArch. On console it might make more sense to go back to menu though ...
+ if (load_menu_game())
+ g_extern.lifecycle_mode_state |= (1ULL << MODE_GAME);
+ else
+ {
+#ifdef RARCH_CONSOLE
+ g_extern.lifecycle_mode_state |= (1ULL << MODE_MENU);
+#else
+ return;
+#endif
+ }
+
+ g_extern.lifecycle_mode_state &= ~(1ULL << MODE_LOAD_GAME);
+ }
+ else if (g_extern.lifecycle_mode_state & (1ULL << MODE_GAME))
+ {
+ bool r;
+ if (g_extern.is_paused && !g_extern.is_oneshot)
+ r = rarch_main_idle_iterate();
+ else
+ r = rarch_main_iterate();
+ if (!r)
+ g_extern.lifecycle_mode_state &= ~(1ULL << MODE_GAME);
+ }
+ else if (g_extern.lifecycle_mode_state & (1ULL << MODE_MENU))
+ {
+ g_extern.lifecycle_mode_state |= 1ULL << MODE_MENU_PREINIT;
+ // Menu should always run with vsync on.
+ video_set_nonblock_state_func(false);
+
+ if (driver.audio_data)
+ audio_stop_func();
+
+ menuloop = true;
+ }
+ else
+ {
+ g_extern.system.shutdown = true;
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ emscripten_set_canvas_size(800, 600);
+
+ rarch_main_clear_state();
+ rarch_init_msg_queue();
+
+ int init_ret;
+ if ((init_ret = rarch_main_init(argc, argv))) return init_ret;
+
+#ifdef HAVE_MENU
+ menu_init();
+ g_extern.lifecycle_mode_state |= 1ULL << MODE_GAME;
+
+ // If we started a ROM directly from command line,
+ // push it to ROM history.
+ if (!g_extern.libretro_dummy)
+ menu_rom_history_push_current();
+#endif
+
+ emscripten_set_main_loop(mainloop, g_settings.video.vsync ? 0 : INT_MAX, 1);
+
+ return 0;
+}
diff --git a/frontend/menu/menu_common.c b/frontend/menu/menu_common.c
index 69c66818a8..582daeb3ff 100644
--- a/frontend/menu/menu_common.c
+++ b/frontend/menu/menu_common.c
@@ -444,27 +444,18 @@ void load_menu_game_history(unsigned game_index)
rom_history_get_index(rgui->history,
game_index, &path, &core_path, &core_name);
- strlcpy(g_settings.libretro, core_path, sizeof(g_settings.libretro));
+ rarch_environment_cb(RETRO_ENVIRONMENT_SET_LIBRETRO_PATH, (void*)core_path);
if (path)
- {
rgui->load_no_rom = false;
- strlcpy(g_extern.fullpath, path, sizeof(g_extern.fullpath));
- }
else
- {
rgui->load_no_rom = true;
- *g_extern.fullpath = '\0';
- }
-#if !defined( HAVE_DYNAMIC) && defined(RARCH_CONSOLE)
- g_extern.lifecycle_mode_state &= ~(1ULL << MODE_GAME);
- g_extern.lifecycle_mode_state |= (1ULL << MODE_EXITSPAWN);
- g_extern.lifecycle_mode_state |= (1ULL << MODE_EXITSPAWN_START_GAME);
-#elif defined(HAVE_DYNAMIC)
+ rarch_environment_cb(RETRO_ENVIRONMENT_EXEC, (void*)path);
+
+#if defined(HAVE_DYNAMIC)
libretro_free_system_info(&rgui->info);
libretro_get_system_info(g_settings.libretro, &rgui->info, NULL);
- g_extern.lifecycle_mode_state |= (1ULL << MODE_LOAD_GAME);
#endif
}
@@ -713,7 +704,7 @@ static uint64_t rgui_input(void)
#ifdef HAVE_OVERLAY
for (unsigned i = 0; i < DEVICE_NAV_LAST; i++)
- input_state |= driver.overlay_state & menu_nav_binds[0][i].joykey ? (1ULL << i) : 0;
+ input_state |= driver.overlay_state.buttons & menu_nav_binds[0][i].joykey ? (1ULL << i) : 0;
#endif
#else
static const int maps[] = {
@@ -734,7 +725,7 @@ static uint64_t rgui_input(void)
input_state |= input_input_state_func(binds,
0, RETRO_DEVICE_JOYPAD, 0, maps[i + 0]) ? (1ULL << maps[i + 1]) : 0;
#ifdef HAVE_OVERLAY
- input_state |= (driver.overlay_state & (UINT64_C(1) << maps[i + 0])) ? (1ULL << maps[i + 1]) : 0;
+ input_state |= (driver.overlay_state.buttons & (UINT64_C(1) << maps[i + 0])) ? (1ULL << maps[i + 1]) : 0;
#endif
}
diff --git a/frontend/menu/menu_common.h b/frontend/menu/menu_common.h
index a3293785ed..efa08046f0 100644
--- a/frontend/menu/menu_common.h
+++ b/frontend/menu/menu_common.h
@@ -118,6 +118,11 @@ typedef enum
RGUI_SETTINGS_VIDEO_VSYNC,
RGUI_SETTINGS_VIDEO_HARD_SYNC,
RGUI_SETTINGS_VIDEO_HARD_SYNC_FRAMES,
+ RGUI_SETTINGS_VIDEO_BLACK_FRAME_INSERTION,
+ RGUI_SETTINGS_VIDEO_SWAP_INTERVAL,
+ RGUI_SETTINGS_VIDEO_WINDOW_SCALE_X,
+ RGUI_SETTINGS_VIDEO_WINDOW_SCALE_Y,
+ RGUI_SETTINGS_VIDEO_CROP_OVERSCAN,
RGUI_SETTINGS_VIDEO_REFRESH_RATE_AUTO,
RGUI_SETTINGS_VIDEO_OPTIONS_LAST,
#ifdef HAVE_SHADER_MANAGER
@@ -157,6 +162,7 @@ typedef enum
RGUI_SHADER_DIR_PATH,
RGUI_SAVESTATE_DIR_PATH,
RGUI_SAVEFILE_DIR_PATH,
+ RGUI_LIBRETRO_DIR_PATH,
#ifdef HAVE_OVERLAY
RGUI_OVERLAY_DIR_PATH,
#endif
diff --git a/frontend/menu/rgui.c b/frontend/menu/rgui.c
index b95cea36e7..8357f27774 100644
--- a/frontend/menu/rgui.c
+++ b/frontend/menu/rgui.c
@@ -215,6 +215,7 @@ static bool menu_type_is_directory_browser(unsigned type)
type == RGUI_SHADER_DIR_PATH ||
#endif
type == RGUI_SAVESTATE_DIR_PATH ||
+ type == RGUI_LIBRETRO_DIR_PATH ||
type == RGUI_SAVEFILE_DIR_PATH ||
#ifdef HAVE_OVERLAY
type == RGUI_OVERLAY_DIR_PATH ||
@@ -266,6 +267,10 @@ rgui_handle_t *rgui_init(void)
aspectratio_lut[ASPECT_RATIO_CUSTOM].value =
(float)custom->width / custom->height;
}
+ else if (DEFAULT_ASPECT_RATIO > 0.0f)
+ aspectratio_lut[ASPECT_RATIO_CUSTOM].value = DEFAULT_ASPECT_RATIO;
+ else
+ aspectratio_lut[ASPECT_RATIO_CUSTOM].value = 4.0f / 3.0f; // Something arbitrary
return rgui;
}
@@ -414,6 +419,10 @@ static void render_text(rgui_handle_t *rgui)
rgui->selection_ptr - TERM_HEIGHT / 2 : 0;
size_t end = rgui->selection_ptr + TERM_HEIGHT <= rgui->selection_buf->size ?
rgui->selection_ptr + TERM_HEIGHT : rgui->selection_buf->size;
+
+ // Do not scroll if all items are visible.
+ if (rgui->selection_buf->size <= TERM_HEIGHT)
+ begin = 0;
if (end - begin > TERM_HEIGHT)
end = begin + TERM_HEIGHT;
@@ -463,6 +472,8 @@ static void render_text(rgui_handle_t *rgui)
snprintf(title, sizeof(title), "SHADER DIR %s", dir);
else if (menu_type == RGUI_SAVESTATE_DIR_PATH)
snprintf(title, sizeof(title), "SAVESTATE DIR %s", dir);
+ else if (menu_type == RGUI_LIBRETRO_DIR_PATH)
+ snprintf(title, sizeof(title), "LIBRETRO DIR %s", dir);
else if (menu_type == RGUI_SAVEFILE_DIR_PATH)
snprintf(title, sizeof(title), "SAVEFILE DIR %s", dir);
#ifdef HAVE_OVERLAY
@@ -594,6 +605,21 @@ static void render_text(rgui_handle_t *rgui)
case RGUI_SETTINGS_VIDEO_HARD_SYNC:
strlcpy(type_str, g_settings.video.hard_sync ? "ON" : "OFF", sizeof(type_str));
break;
+ case RGUI_SETTINGS_VIDEO_BLACK_FRAME_INSERTION:
+ strlcpy(type_str, g_settings.video.black_frame_insertion ? "ON" : "OFF", sizeof(type_str));
+ break;
+ case RGUI_SETTINGS_VIDEO_SWAP_INTERVAL:
+ snprintf(type_str, sizeof(type_str), "%u", g_settings.video.swap_interval);
+ break;
+ case RGUI_SETTINGS_VIDEO_WINDOW_SCALE_X:
+ snprintf(type_str, sizeof(type_str), "%.1fx", g_settings.video.xscale);
+ break;
+ case RGUI_SETTINGS_VIDEO_WINDOW_SCALE_Y:
+ snprintf(type_str, sizeof(type_str), "%.1fx", g_settings.video.yscale);
+ break;
+ case RGUI_SETTINGS_VIDEO_CROP_OVERSCAN:
+ strlcpy(type_str, g_settings.video.crop_overscan ? "ON" : "OFF", sizeof(type_str));
+ break;
case RGUI_SETTINGS_VIDEO_HARD_SYNC_FRAMES:
snprintf(type_str, sizeof(type_str), "%u", g_settings.video.hard_sync_frames);
break;
@@ -629,10 +655,7 @@ static void render_text(rgui_handle_t *rgui)
w = 5;
break;
case RGUI_SETTINGS_REWIND_ENABLE:
- if (g_settings.rewind_enable)
- strlcpy(type_str, "ON", sizeof(type_str));
- else
- strlcpy(type_str, "OFF", sizeof(type_str));
+ strlcpy(type_str, g_settings.rewind_enable ? "ON" : "OFF", sizeof(type_str));
break;
case RGUI_SETTINGS_REWIND_GRANULARITY:
snprintf(type_str, sizeof(type_str), "%u", g_settings.rewind_granularity);
@@ -648,10 +671,7 @@ static void render_text(rgui_handle_t *rgui)
snprintf(type_str, sizeof(type_str), "%d", g_extern.state_slot);
break;
case RGUI_SETTINGS_AUDIO_MUTE:
- if (g_extern.audio_data.mute)
- strlcpy(type_str, "ON", sizeof(type_str));
- else
- strlcpy(type_str, "OFF", sizeof(type_str));
+ strlcpy(type_str, g_extern.audio_data.mute ? "ON" : "OFF", sizeof(type_str));
break;
case RGUI_SETTINGS_AUDIO_CONTROL_RATE_DELTA:
snprintf(type_str, sizeof(type_str), "%.3f", g_settings.audio.rate_control_delta);
@@ -660,42 +680,27 @@ static void render_text(rgui_handle_t *rgui)
snprintf(type_str, sizeof(type_str), (g_extern.lifecycle_mode_state & (1ULL << MODE_FPS_DRAW)) ? "ON" : "OFF");
break;
case RGUI_BROWSER_DIR_PATH:
- if (*g_settings.rgui_browser_directory)
- strlcpy(type_str, g_settings.rgui_browser_directory, sizeof(type_str));
- else
- strlcpy(type_str, "", sizeof(type_str));
+ strlcpy(type_str, *g_settings.rgui_browser_directory ? g_settings.rgui_browser_directory : "", sizeof(type_str));
break;
case RGUI_SAVEFILE_DIR_PATH:
- if (*g_extern.savefile_dir)
- strlcpy(type_str, g_extern.savefile_dir, sizeof(type_str));
- else
- strlcpy(type_str, "", sizeof(type_str));
+ strlcpy(type_str, *g_extern.savefile_dir ? g_extern.savefile_dir : "", sizeof(type_str));
break;
#ifdef HAVE_OVERLAY
case RGUI_OVERLAY_DIR_PATH:
- if (*g_extern.overlay_dir)
- strlcpy(type_str, g_extern.overlay_dir, sizeof(type_str));
- else
- strlcpy(type_str, "", sizeof(type_str));
+ strlcpy(type_str, *g_extern.overlay_dir ? g_extern.overlay_dir : "", sizeof(type_str));
break;
#endif
case RGUI_SAVESTATE_DIR_PATH:
- if (*g_extern.savestate_dir)
- strlcpy(type_str, g_extern.savestate_dir, sizeof(type_str));
- else
- strlcpy(type_str, "", sizeof(type_str));
+ strlcpy(type_str, *g_extern.savestate_dir ? g_extern.savestate_dir : "", sizeof(type_str));
+ break;
+ case RGUI_LIBRETRO_DIR_PATH:
+ strlcpy(type_str, *rgui->libretro_dir ? rgui->libretro_dir : "", sizeof(type_str));
break;
case RGUI_SHADER_DIR_PATH:
- if (*g_settings.video.shader_dir)
- strlcpy(type_str, g_settings.video.shader_dir, sizeof(type_str));
- else
- strlcpy(type_str, "", sizeof(type_str));
+ strlcpy(type_str, *g_settings.video.shader_dir ? g_settings.video.shader_dir : "", sizeof(type_str));
break;
case RGUI_SYSTEM_DIR_PATH:
- if (*g_settings.system_directory)
- strlcpy(type_str, g_settings.system_directory, sizeof(type_str));
- else
- strlcpy(type_str, "", sizeof(type_str));
+ strlcpy(type_str, *g_settings.system_directory ? g_settings.system_directory : "", sizeof(type_str));
break;
case RGUI_SETTINGS_DISK_INDEX:
{
@@ -1385,6 +1390,10 @@ static int rgui_settings_toggle_setting(rgui_handle_t *rgui, unsigned setting, r
if (action == RGUI_ACTION_START)
*g_extern.savestate_dir = '\0';
break;
+ case RGUI_LIBRETRO_DIR_PATH:
+ if (action == RGUI_ACTION_START)
+ *rgui->libretro_dir = '\0';
+ break;
case RGUI_SHADER_DIR_PATH:
if (action == RGUI_ACTION_START)
*g_settings.video.shader_dir = '\0';
@@ -1496,13 +1505,20 @@ static void rgui_settings_video_options_populate_entries(rgui_handle_t *rgui)
rgui_list_push(rgui->selection_buf, "Integer Scale", RGUI_SETTINGS_VIDEO_INTEGER_SCALE, 0);
rgui_list_push(rgui->selection_buf, "Aspect Ratio", RGUI_SETTINGS_VIDEO_ASPECT_RATIO, 0);
rgui_list_push(rgui->selection_buf, "Custom Ratio", RGUI_SETTINGS_CUSTOM_VIEWPORT, 0);
-#ifndef RARCH_PERFORMANCE_MODE
+#if !defined(RARCH_CONSOLE) && !defined(RARCH_MOBILE)
rgui_list_push(rgui->selection_buf, "Toggle Fullscreen", RGUI_SETTINGS_TOGGLE_FULLSCREEN, 0);
#endif
rgui_list_push(rgui->selection_buf, "Rotation", RGUI_SETTINGS_VIDEO_ROTATION, 0);
rgui_list_push(rgui->selection_buf, "VSync", RGUI_SETTINGS_VIDEO_VSYNC, 0);
rgui_list_push(rgui->selection_buf, "Hard GPU Sync", RGUI_SETTINGS_VIDEO_HARD_SYNC, 0);
rgui_list_push(rgui->selection_buf, "Hard GPU Sync Frames", RGUI_SETTINGS_VIDEO_HARD_SYNC_FRAMES, 0);
+ rgui_list_push(rgui->selection_buf, "Black Frame Insertion", RGUI_SETTINGS_VIDEO_BLACK_FRAME_INSERTION, 0);
+ rgui_list_push(rgui->selection_buf, "VSync Swap Interval", RGUI_SETTINGS_VIDEO_SWAP_INTERVAL, 0);
+#if !defined(RARCH_CONSOLE) && !defined(RARCH_MOBILE)
+ rgui_list_push(rgui->selection_buf, "Windowed Scale (X)", RGUI_SETTINGS_VIDEO_WINDOW_SCALE_X, 0);
+ rgui_list_push(rgui->selection_buf, "Windowed Scale (Y)", RGUI_SETTINGS_VIDEO_WINDOW_SCALE_Y, 0);
+#endif
+ rgui_list_push(rgui->selection_buf, "Crop Overscan (reload)", RGUI_SETTINGS_VIDEO_CROP_OVERSCAN, 0);
rgui_list_push(rgui->selection_buf, "Estimated Monitor FPS", RGUI_SETTINGS_VIDEO_REFRESH_RATE_AUTO, 0);
}
@@ -1850,12 +1866,10 @@ static int video_option_toggle_setting(rgui_handle_t *rgui, unsigned setting, rg
driver.video_poke->set_aspect_ratio(driver.video_data, g_settings.video.aspect_ratio_idx);
break;
-#ifndef RARCH_PERFORMANCE_MODE
case RGUI_SETTINGS_TOGGLE_FULLSCREEN:
if (action == RGUI_ACTION_OK)
rarch_set_fullscreen(!g_settings.video.fullscreen);
break;
-#endif
#ifdef GEKKO
case RGUI_SETTINGS_VIDEO_RESOLUTION:
@@ -1932,6 +1946,105 @@ static int video_option_toggle_setting(rgui_handle_t *rgui, unsigned setting, rg
}
break;
+ case RGUI_SETTINGS_VIDEO_BLACK_FRAME_INSERTION:
+ switch (action)
+ {
+ case RGUI_ACTION_START:
+ g_settings.video.black_frame_insertion = false;
+ break;
+
+ case RGUI_ACTION_LEFT:
+ case RGUI_ACTION_RIGHT:
+ case RGUI_ACTION_OK:
+ g_settings.video.black_frame_insertion = !g_settings.video.black_frame_insertion;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case RGUI_SETTINGS_VIDEO_CROP_OVERSCAN:
+ switch (action)
+ {
+ case RGUI_ACTION_START:
+ g_settings.video.crop_overscan = true;
+ break;
+
+ case RGUI_ACTION_LEFT:
+ case RGUI_ACTION_RIGHT:
+ case RGUI_ACTION_OK:
+ g_settings.video.crop_overscan = !g_settings.video.crop_overscan;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case RGUI_SETTINGS_VIDEO_WINDOW_SCALE_X:
+ case RGUI_SETTINGS_VIDEO_WINDOW_SCALE_Y:
+ {
+ float *scale = setting == RGUI_SETTINGS_VIDEO_WINDOW_SCALE_X ? &g_settings.video.xscale : &g_settings.video.yscale;
+ float old_scale = *scale;
+
+ switch (action)
+ {
+ case RGUI_ACTION_START:
+ *scale = 3.0f;
+ break;
+
+ case RGUI_ACTION_LEFT:
+ *scale -= 1.0f;
+ break;
+
+ case RGUI_ACTION_RIGHT:
+ *scale += 1.0f;
+ break;
+
+ default:
+ break;
+ }
+
+ *scale = roundf(*scale);
+ *scale = max(*scale, 1.0f);
+
+ if (old_scale != *scale && !g_settings.video.fullscreen)
+ rarch_set_fullscreen(g_settings.video.fullscreen); // Reinit video driver.
+
+ break;
+ }
+
+ case RGUI_SETTINGS_VIDEO_SWAP_INTERVAL:
+ {
+ unsigned old = g_settings.video.swap_interval;
+ switch (action)
+ {
+ case RGUI_ACTION_START:
+ g_settings.video.swap_interval = 1;
+ break;
+
+ case RGUI_ACTION_LEFT:
+ g_settings.video.swap_interval--;
+ break;
+
+ case RGUI_ACTION_RIGHT:
+ case RGUI_ACTION_OK:
+ g_settings.video.swap_interval++;
+ break;
+
+ default:
+ break;
+ }
+
+ g_settings.video.swap_interval = min(g_settings.video.swap_interval, 4);
+ g_settings.video.swap_interval = max(g_settings.video.swap_interval, 1);
+ if (old != g_settings.video.swap_interval && driver.video && driver.video_data)
+ video_set_nonblock_state_func(false); // This will update the current swap interval. Since we're in RGUI now, always apply VSync.
+
+ break;
+ }
+
case RGUI_SETTINGS_VIDEO_HARD_SYNC_FRAMES:
switch (action)
{
@@ -1992,6 +2105,9 @@ static void rgui_settings_path_populate_entries(rgui_handle_t *rgui)
{
rgui_list_clear(rgui->selection_buf);
rgui_list_push(rgui->selection_buf, "Browser Directory", RGUI_BROWSER_DIR_PATH, 0);
+#ifdef HAVE_DYNAMIC
+ rgui_list_push(rgui->selection_buf, "Core Directory", RGUI_LIBRETRO_DIR_PATH, 0);
+#endif
#ifdef HAVE_SHADER_MANAGER
rgui_list_push(rgui->selection_buf, "Shader Directory", RGUI_SHADER_DIR_PATH, 0);
#endif
@@ -2650,7 +2766,8 @@ int rgui_iterate(rgui_handle_t *rgui)
// Core selection on non-console just updates directory listing.
// Will take affect on new ROM load.
#elif defined(GEKKO) && defined(HW_RVL)
- strlcpy(g_settings.libretro, path, sizeof(g_settings.libretro)); // Is this supposed to be here?
+ rarch_environment_cb(RETRO_ENVIRONMENT_SET_LIBRETRO_PATH, (void*)path);
+
fill_pathname_join(g_extern.fullpath, default_paths.core_dir,
SALAMANDER_FILE, sizeof(g_extern.fullpath));
g_extern.lifecycle_mode_state &= ~(1ULL << MODE_GAME);
@@ -2714,6 +2831,11 @@ int rgui_iterate(rgui_handle_t *rgui)
strlcpy(g_extern.savestate_dir, dir, sizeof(g_extern.savestate_dir));
rgui_flush_menu_stack_type(rgui, RGUI_SETTINGS_PATH_OPTIONS);
}
+ else if (menu_type == RGUI_LIBRETRO_DIR_PATH)
+ {
+ strlcpy(rgui->libretro_dir, dir, sizeof(g_extern.savestate_dir));
+ rgui_flush_menu_stack_type(rgui, RGUI_SETTINGS_PATH_OPTIONS);
+ }
else if (menu_type == RGUI_SHADER_DIR_PATH)
{
strlcpy(g_settings.video.shader_dir, dir, sizeof(g_settings.video.shader_dir));
diff --git a/frontend/menu/rmenu.c b/frontend/menu/rmenu.c
index 691232bad3..19aad8e7f3 100644
--- a/frontend/menu/rmenu.c
+++ b/frontend/menu/rmenu.c
@@ -460,7 +460,6 @@ static int select_file(void *data, uint64_t input)
char extensions[128];
char comment[128];
char path[PATH_MAX];
- bool ret = true;
bool pop_menu_stack = false;
font_params_t font_parms = {0};
@@ -495,7 +494,7 @@ static int select_file(void *data, uint64_t input)
if (input & (1ULL << DEVICE_NAV_B))
{
if (filebrowser_iterate(rgui->browser, FILEBROWSER_ACTION_PATH_ISDIR))
- ret = filebrowser_iterate(rgui->browser, FILEBROWSER_ACTION_OK);
+ filebrowser_iterate(rgui->browser, FILEBROWSER_ACTION_OK);
else
{
strlcpy(path, rgui->browser->current_dir.path, sizeof(path));
@@ -560,7 +559,7 @@ static int select_file(void *data, uint64_t input)
true, menu_texture->width, menu_texture->height, 1.0f);
break;
case LIBRETRO_CHOICE:
- strlcpy(g_settings.libretro, path, sizeof(g_settings.libretro));
+ rarch_environment_cb(RETRO_ENVIRONMENT_SET_LIBRETRO_PATH, (void*)path);
g_extern.lifecycle_mode_state |= (1ULL << MODE_EXITSPAWN);
return -1;
}
diff --git a/frontend/menu/rmenu_xui.cpp b/frontend/menu/rmenu_xui.cpp
index 8b41252f44..815d7ca2fa 100644
--- a/frontend/menu/rmenu_xui.cpp
+++ b/frontend/menu/rmenu_xui.cpp
@@ -1222,8 +1222,11 @@ HRESULT CRetroArchCoreBrowser::OnNotifyPress( HXUIOBJ hObjPressed, BOOL& bHandle
wcstombs(str_buffer, (const wchar_t *)XuiListGetText(m_menulist, index), sizeof(str_buffer));
if(path_file_exists(rgui->browser->list->elems[index].data))
{
- snprintf(g_settings.libretro, sizeof(g_settings.libretro), "%s\\%s",
- rgui->browser->current_dir.directory_path, str_buffer);
+ struct retro_variable var;
+ var.key = "core_path";
+ snprintf(var.value, sizeof(var.value), "%s\\%s", rgui->browser->current_dir.directory_path, str_buffer);
+ rarch_environment_cb(RETRO_ENVIRONMENT_SET_LIBRETRO_PATH, &var);
+
g_extern.lifecycle_mode_state |= (1ULL << MODE_EXITSPAWN);
process_input_ret = -1;
}
diff --git a/frontend/platform/platform_apple.c b/frontend/platform/platform_apple.c
index 5c413ac4d2..a35ec8a1f2 100644
--- a/frontend/platform/platform_apple.c
+++ b/frontend/platform/platform_apple.c
@@ -15,7 +15,7 @@
#include
#include
-#include "../../apple/RetroArch/rarch_wrapper.h"
+#include "../../apple/common/rarch_wrapper.h"
#include "../frontend_context.h"
@@ -48,20 +48,6 @@ void apple_frontend_post_event(void (*fn)(void*), void* userdata)
pthread_mutex_unlock(&apple_event_queue_lock);
}
-static void apple_free_main_wrap(struct rarch_main_wrap* wrap)
-{
- if (wrap)
- {
- free((char*)wrap->libretro_path);
- free((char*)wrap->rom_path);
- free((char*)wrap->sram_path);
- free((char*)wrap->state_path);
- free((char*)wrap->config_path);
- }
-
- free(wrap);
-}
-
static void process_events(void)
{
pthread_mutex_lock(&apple_event_queue_lock);
@@ -83,24 +69,8 @@ static void system_shutdown(bool force)
dispatch_async_f(dispatch_get_main_queue(), 0, apple_rarch_exited);
}
-static void environment_get(int argc, char *argv[], void *args)
-{
- (void)argc;
- (void)argv;
- (void)args;
-
-#ifdef IOS
- char* system_directory = ios_get_rarch_system_directory();
- strlcpy(g_extern.savestate_dir, system_directory, sizeof(g_extern.savestate_dir));
- strlcpy(g_extern.savefile_dir, system_directory, sizeof(g_extern.savefile_dir));
- free(system_directory);
-
- config_load();
-#endif
-}
-
const frontend_ctx_driver_t frontend_ctx_apple = {
- environment_get, /* environment_get */
+ NULL, /* environment_get */
NULL, /* init */
NULL, /* deinit */
NULL, /* exitspawn */
diff --git a/frontend/platform/platform_gx.c b/frontend/platform/platform_gx.c
index 102514d0ab..2851e55b38 100644
--- a/frontend/platform/platform_gx.c
+++ b/frontend/platform/platform_gx.c
@@ -18,7 +18,7 @@
#include
#include "../../driver.h"
#include "../../general.h"
-#include "../../libretro.h"
+#include "../../libretro_private.h"
#include "../../console/rarch_console.h"
#include "../../file.h"
@@ -367,7 +367,11 @@ static int system_process_args(int argc, char *argv[], void *args)
// a big hack: sometimes salamander doesn't save the new core it loads on first boot,
// so we make sure g_settings.libretro is set here
if (!g_settings.libretro[0] && argc >= 1 && strrchr(argv[0], '/'))
- strlcpy(g_settings.libretro, strrchr(argv[0], '/') + 1, sizeof(g_settings.libretro));
+ {
+ char path[PATH_MAX];
+ strlcpy(path, strrchr(argv[0], '/') + 1, sizeof(path));
+ rarch_environment_cb(RETRO_ENVIRONMENT_SET_LIBRETRO_PATH, path);
+ }
if (argc > 2 && argv[1] != NULL && argv[2] != NULL)
{
diff --git a/frontend/platform/platform_qnx.c b/frontend/platform/platform_qnx.c
index 1f2e4f3080..d0864d7a0d 100644
--- a/frontend/platform/platform_qnx.c
+++ b/frontend/platform/platform_qnx.c
@@ -20,6 +20,8 @@
#include "../../boolean.h"
#include
#include
+#include "../../dynamic.h"
+#include "../../libretro_private.h"
static void get_environment_settings(int argc, char *argv[], void *args)
{
@@ -28,7 +30,8 @@ static void get_environment_settings(int argc, char *argv[], void *args)
/* FIXME - should this apply for both BB10 and PB? */
#if defined(__QNX__) && !defined(HAVE_BB10)
- strlcpy(g_settings.libretro, "app/native/lib", sizeof(g_settings.libretro));
+ rarch_environment_cb(RETRO_ENVIRONMENT_SET_LIBRETRO_PATH, (void*)"app/native/lib");
+
strlcpy(g_extern.config_path, "app/native/retroarch.cfg", sizeof(g_extern.config_path));
strlcpy(g_settings.video.shader_dir, "app/native/shaders_glsl", sizeof(g_settings.video.shader_dir));
#endif
diff --git a/general.h b/general.h
index ca07012988..5632ba6086 100644
--- a/general.h
+++ b/general.h
@@ -41,9 +41,9 @@
#ifndef PACKAGE_VERSION
#ifdef __QNX__
/* FIXME - avoid too many decimal points in number error */
-#define PACKAGE_VERSION "0994"
+#define PACKAGE_VERSION "0996"
#else
-#define PACKAGE_VERSION "0.9.9.4"
+#define PACKAGE_VERSION "0.9.9.6"
#endif
#endif
@@ -159,6 +159,8 @@ struct settings
unsigned fullscreen_y;
bool vsync;
bool hard_sync;
+ bool black_frame_insertion;
+ unsigned swap_interval;
unsigned hard_sync_frames;
bool smooth;
bool force_aspect;
@@ -201,6 +203,7 @@ struct settings
char driver[32];
bool enable;
unsigned out_rate;
+ unsigned block_frames;
float in_rate;
char device[PATH_MAX];
unsigned latency;
@@ -393,7 +396,8 @@ struct global
char valid_extensions[PATH_MAX];
retro_keyboard_event_t key_event;
- retro_audio_callback_t audio_callback;
+
+ struct retro_audio_callback audio_callback;
struct retro_disk_control_callback disk_control;
struct retro_hw_render_callback hw_render_callback;
@@ -471,6 +475,8 @@ struct global
msg_queue_t *msg_queue;
+ bool exec;
+
// Rewind support.
state_manager_t *state_manager;
void *state_buf;
@@ -676,11 +682,7 @@ bool config_save_keybinds(const char *path);
void rarch_game_reset(void);
void rarch_main_clear_state(void);
void rarch_init_system_info(void);
-#ifdef __APPLE__
-void * rarch_main(void *args);
-#else
int rarch_main(int argc, char *argv[]);
-#endif
int rarch_main_init_wrap(const struct rarch_main_wrap *args);
int rarch_main_init(int argc, char *argv[]);
bool rarch_main_idle_iterate(void);
diff --git a/gfx/context/apple_gl_ctx.c b/gfx/context/apple_gl_ctx.c
index 3fc50861b2..2b0b13cb8f 100644
--- a/gfx/context/apple_gl_ctx.c
+++ b/gfx/context/apple_gl_ctx.c
@@ -25,34 +25,7 @@
#include "../shader_glsl.h"
#endif
-#include "../../apple/RetroArch/rarch_wrapper.h"
-
-static bool gfx_ctx_bind_api(enum gfx_ctx_api api, unsigned major, unsigned minor)
-{
- (void)major;
- (void)minor;
-#ifdef IOS
- return api == GFX_CTX_OPENGL_ES_API;
-#else
- return api == GFX_CTX_OPENGL_API;
-#endif
-}
-
-static bool gfx_ctx_set_video_mode(
- unsigned width, unsigned height,
- bool fullscreen)
-{
- (void)width;
- (void)height;
- (void)fullscreen;
- return true;
-}
-
-static void gfx_ctx_update_window_title(void)
-{
- char buf[128];
- gfx_get_fps(buf, sizeof(buf), false);
-}
+#include "../../apple/common/rarch_wrapper.h"
static void gfx_ctx_check_window(bool *quit,
bool *resize, unsigned *width, unsigned *height, unsigned frame_count)
@@ -62,7 +35,7 @@ static void gfx_ctx_check_window(bool *quit,
*quit = false;
unsigned new_width, new_height;
- apple_get_game_view_size(&new_width, &new_height);
+ apple_gfx_ctx_get_video_size(&new_width, &new_height);
if (new_width != *width || new_height != *height)
{
*width = new_width;
@@ -77,44 +50,28 @@ static void gfx_ctx_set_resize(unsigned width, unsigned height)
(void)height;
}
-static bool gfx_ctx_has_focus(void)
-{
- return true;
-}
-
-static void gfx_ctx_swap_buffers(void)
-{
- apple_flip_game_view();
-}
-
static void gfx_ctx_input_driver(const input_driver_t **input, void **input_data)
{
*input = NULL;
*input_data = NULL;
}
-static gfx_ctx_proc_t gfx_ctx_get_proc_address(const char *symbol_name)
-{
- return (gfx_ctx_proc_t)apple_get_proc_address(symbol_name);
-}
-
// The apple_* functions are implemented in apple/RetroArch/RAGameView.m
-
const gfx_ctx_driver_t gfx_ctx_apple = {
- apple_init_game_view,
- apple_destroy_game_view,
- gfx_ctx_bind_api,
- apple_set_game_view_sync,
- gfx_ctx_set_video_mode,
- apple_get_game_view_size,
+ apple_gfx_ctx_init,
+ apple_gfx_ctx_destroy,
+ apple_gfx_ctx_bind_api,
+ apple_gfx_ctx_swap_interval,
+ apple_gfx_ctx_set_video_mode,
+ apple_gfx_ctx_get_video_size,
NULL,
- gfx_ctx_update_window_title,
+ apple_gfx_ctx_update_window_title,
gfx_ctx_check_window,
gfx_ctx_set_resize,
- gfx_ctx_has_focus,
- apple_flip_game_view,
+ apple_gfx_ctx_has_focus,
+ apple_gfx_ctx_swap_buffers,
gfx_ctx_input_driver,
- gfx_ctx_get_proc_address,
+ apple_gfx_ctx_get_proc_address,
NULL,
- "ios",
+ "apple",
};
diff --git a/gfx/context/drm_egl_ctx.c b/gfx/context/drm_egl_ctx.c
index 67bda39585..995a9301c2 100644
--- a/gfx/context/drm_egl_ctx.c
+++ b/gfx/context/drm_egl_ctx.c
@@ -93,6 +93,8 @@ static void sighandler(int sig)
static void gfx_ctx_swap_interval(unsigned interval)
{
g_interval = interval;
+ if (interval > 1)
+ RARCH_WARN("[KMS/EGL]: Swap intervals > 1 currently not supported. Will use swap interval of 1.\n");
}
static void gfx_ctx_check_window(bool *quit,
diff --git a/gfx/context/emscriptenegl_ctx.c b/gfx/context/emscriptenegl_ctx.c
new file mode 100644
index 0000000000..f9b89a42ca
--- /dev/null
+++ b/gfx/context/emscriptenegl_ctx.c
@@ -0,0 +1,275 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2010-2013 - Hans-Kristian Arntzen
+ * Copyright (C) 2012 - Michael Lelli
+ *
+ * RetroArch is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with RetroArch.
+ * If not, see .
+ */
+
+// VideoCore context, for Rasperry Pi.
+
+#include "../../driver.h"
+#include "../gfx_context.h"
+#include "../gl_common.h"
+#include "../gfx_common.h"
+
+#ifdef HAVE_CONFIG_H
+#include "../../config.h"
+#endif
+
+#include
+#include
+
+#include
+#include
+#include
+
+static EGLContext g_egl_ctx;
+static EGLSurface g_egl_surf;
+static EGLDisplay g_egl_dpy;
+static EGLConfig g_config;
+
+static bool g_inited;
+
+static unsigned g_fb_width;
+static unsigned g_fb_height;
+
+static void gfx_ctx_swap_interval(unsigned interval)
+{
+ // no way to control vsync in WebGL
+ (void)interval;
+}
+
+static void gfx_ctx_check_window(bool *quit,
+ bool *resize, unsigned *width, unsigned *height, unsigned frame_count)
+{
+ (void)frame_count;
+ int iWidth, iHeight, isFullscreen;
+
+ emscripten_get_canvas_size(&iWidth, &iHeight, &isFullscreen);
+ *width = (unsigned) iWidth;
+ *height = (unsigned) iHeight;
+
+ if (*width != g_fb_width || *height != g_fb_height)
+ *resize = true;
+ else
+ *resize = false;
+
+ g_fb_width = (unsigned) iWidth;
+ g_fb_height = (unsigned) iHeight;
+ *quit = false;
+}
+
+static void gfx_ctx_swap_buffers(void)
+{
+ // no-op in emscripten, no way to force swap/wait for vsync in browsers
+ //eglSwapBuffers(g_egl_dpy, g_egl_surf);
+}
+
+static void gfx_ctx_set_resize(unsigned width, unsigned height)
+{
+ (void)width;
+ (void)height;
+}
+
+static void gfx_ctx_update_window_title(void)
+{
+ char buf[128];
+ if (gfx_get_fps(buf, sizeof(buf), false))
+ RARCH_LOG("%s\n", buf);
+}
+
+static void gfx_ctx_get_video_size(unsigned *width, unsigned *height)
+{
+ *width = g_fb_width;
+ *height = g_fb_height;
+}
+
+static void gfx_ctx_destroy(void);
+
+static bool gfx_ctx_init(void)
+{
+ EGLint width;
+ EGLint height;
+
+ RARCH_LOG("[EMSCRIPTEN/EGL]: Initializing...\n");
+ if (g_inited)
+ {
+ RARCH_LOG("[EMSCRIPTEN/EGL]: Attempted to re-initialize driver.\n");
+ return true;
+ }
+
+ EGLint num_config;
+
+ static const EGLint attribute_list[] =
+ {
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_NONE
+ };
+
+ static const EGLint context_attributes[] =
+ {
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+ EGL_NONE
+ };
+
+ // get an EGL display connection
+ g_egl_dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ if (!g_egl_dpy)
+ goto error;
+
+ // initialize the EGL display connection
+ if (!eglInitialize(g_egl_dpy, NULL, NULL))
+ goto error;
+
+ // get an appropriate EGL frame buffer configuration
+ if (!eglChooseConfig(g_egl_dpy, attribute_list, &g_config, 1, &num_config))
+ goto error;
+
+ // create an EGL rendering context
+ g_egl_ctx = eglCreateContext(g_egl_dpy, g_config, EGL_NO_CONTEXT, context_attributes);
+ if (!g_egl_ctx)
+ goto error;
+
+ // create an EGL window surface
+ g_egl_surf = eglCreateWindowSurface(g_egl_dpy, g_config, 0, NULL);
+ if (!g_egl_surf)
+ goto error;
+
+ // connect the context to the surface
+ if (!eglMakeCurrent(g_egl_dpy, g_egl_surf, g_egl_surf, g_egl_ctx))
+ goto error;
+
+ eglQuerySurface(g_egl_dpy, g_egl_surf, EGL_WIDTH, &width);
+ eglQuerySurface(g_egl_dpy, g_egl_surf, EGL_HEIGHT, &height);
+ g_fb_width = width;
+ g_fb_height = height;
+ RARCH_LOG("[EMSCRIPTEN/EGL]: Dimensions: %ux%u\n", width, height);
+
+ return true;
+
+error:
+ gfx_ctx_destroy();
+ return false;
+}
+
+static bool gfx_ctx_set_video_mode(
+ unsigned width, unsigned height,
+ bool fullscreen)
+{
+ if (g_inited)
+ return false;
+
+ g_inited = true;
+ return true;
+}
+
+static bool gfx_ctx_bind_api(enum gfx_ctx_api api, unsigned major, unsigned minor)
+{
+ (void)major;
+ (void)minor;
+ switch (api)
+ {
+ case GFX_CTX_OPENGL_ES_API:
+ return eglBindAPI(EGL_OPENGL_ES_API);
+ default:
+ return false;
+ }
+}
+
+static void gfx_ctx_destroy(void)
+{
+ if (g_egl_dpy)
+ {
+ eglMakeCurrent(g_egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+ if (g_egl_ctx)
+ {
+ eglDestroyContext(g_egl_dpy, g_egl_ctx);
+ }
+
+ if (g_egl_surf)
+ {
+ eglDestroySurface(g_egl_dpy, g_egl_surf);
+ }
+
+ eglTerminate(g_egl_dpy);
+ }
+
+ g_egl_ctx = NULL;
+ g_egl_surf = NULL;
+ g_egl_dpy = NULL;
+ g_config = 0;
+ g_inited = false;
+}
+
+static void gfx_ctx_input_driver(const input_driver_t **input, void **input_data)
+{
+ *input = NULL;
+
+ void *rwebinput = input_rwebinput.init();
+
+ if (rwebinput)
+ {
+ *input = &input_rwebinput;
+ *input_data = rwebinput;
+ }
+}
+
+static bool gfx_ctx_has_focus(void)
+{
+ return g_inited;
+}
+
+static gfx_ctx_proc_t gfx_ctx_get_proc_address(const char *symbol)
+{
+ return eglGetProcAddress(symbol);
+}
+
+static float gfx_ctx_translate_aspect(unsigned width, unsigned height)
+{
+ return (float)width / height;
+}
+
+static bool gfx_ctx_init_egl_image_buffer(const video_info_t *video)
+{
+ return false;
+}
+
+static bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, unsigned index, void **image_handle)
+{
+ return false;
+}
+
+const gfx_ctx_driver_t gfx_ctx_emscripten = {
+ gfx_ctx_init,
+ gfx_ctx_destroy,
+ gfx_ctx_bind_api,
+ gfx_ctx_swap_interval,
+ gfx_ctx_set_video_mode,
+ gfx_ctx_get_video_size,
+ gfx_ctx_translate_aspect,
+ gfx_ctx_update_window_title,
+ gfx_ctx_check_window,
+ gfx_ctx_set_resize,
+ gfx_ctx_has_focus,
+ gfx_ctx_swap_buffers,
+ gfx_ctx_input_driver,
+ gfx_ctx_get_proc_address,
+ gfx_ctx_init_egl_image_buffer,
+ gfx_ctx_write_egl_image,
+ NULL,
+ "emscripten",
+};
diff --git a/gfx/context/glx_ctx.c b/gfx/context/glx_ctx.c
index a4d08652e1..cc64267351 100644
--- a/gfx/context/glx_ctx.c
+++ b/gfx/context/glx_ctx.c
@@ -42,6 +42,7 @@ static GLXFBConfig g_fbc;
static unsigned g_major;
static unsigned g_minor;
static bool g_core;
+static bool g_debug;
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*,
GLXFBConfig, GLXContext, Bool, const int*);
@@ -229,24 +230,22 @@ static bool gfx_ctx_init(void)
int major, minor;
glXQueryVersion(g_dpy, &major, &minor);
- if (g_major * 1000 + g_minor >= 3001) // Core context
- {
- g_core = true;
- // GLX 1.4+ required.
- if ((major * 1000 + minor) < 1004)
- goto error;
- glx_create_context_attribs = (glXCreateContextAttribsARBProc)glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB");
- if (!glx_create_context_attribs)
- goto error;
- }
- else
- {
- g_core = false;
- // GLX 1.3+ required.
- if ((major * 1000 + minor) < 1003)
- goto error;
- }
+ // GLX 1.3+ minimum required.
+ if ((major * 1000 + minor) < 1003)
+ goto error;
+
+ glx_create_context_attribs = (glXCreateContextAttribsARBProc)glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB");
+
+#ifdef GL_DEBUG
+ g_debug = true;
+#else
+ g_debug = g_extern.system.hw_render_callback.debug_context;
+#endif
+
+ g_core = (g_major * 1000 + g_minor) >= 3001; // Have to use ContextAttribs
+ if ((g_core || g_debug) && !glx_create_context_attribs)
+ goto error;
int nelements;
fbcs = glXChooseFBConfig(g_dpy, DefaultScreen(g_dpy),
@@ -376,16 +375,28 @@ static bool gfx_ctx_set_video_mode(
if (!g_ctx)
{
- if (g_core)
+ if (g_core || g_debug)
{
- const int attribs[] = {
- GLX_CONTEXT_MAJOR_VERSION_ARB, (int)g_major,
- GLX_CONTEXT_MINOR_VERSION_ARB, (int)g_minor,
- GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
- GLX_CONTEXT_FLAGS_ARB, g_extern.system.hw_render_callback.debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0,
- None,
- };
+ int attribs[16];
+ int *aptr = attribs;
+ if (g_core)
+ {
+ *aptr++ = GLX_CONTEXT_MAJOR_VERSION_ARB;
+ *aptr++ = g_major;
+ *aptr++ = GLX_CONTEXT_MINOR_VERSION_ARB;
+ *aptr++ = g_minor;
+ *aptr++ = GLX_CONTEXT_PROFILE_MASK_ARB;
+ *aptr++ = GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
+ }
+
+ if (g_debug)
+ {
+ *aptr++ = GLX_CONTEXT_FLAGS_ARB;
+ *aptr++ = GLX_CONTEXT_DEBUG_BIT_ARB;
+ }
+
+ *aptr = None;
g_ctx = glx_create_context_attribs(g_dpy, g_fbc, NULL, True, attribs);
}
else
diff --git a/gfx/context/vc_egl_ctx.c b/gfx/context/vc_egl_ctx.c
index b9097751ff..1db9a28f8b 100644
--- a/gfx/context/vc_egl_ctx.c
+++ b/gfx/context/vc_egl_ctx.c
@@ -284,7 +284,7 @@ static void gfx_ctx_destroy(void)
if (g_egl_ctx)
{
- gfx_ctx_bind_api(g_api);
+ gfx_ctx_bind_api(g_api, 0, 0);
eglMakeCurrent(g_egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroyContext(g_egl_dpy, g_egl_ctx);
}
@@ -298,7 +298,7 @@ static void gfx_ctx_destroy(void)
if (g_egl_surf)
{
- gfx_ctx_bind_api(g_api);
+ gfx_ctx_bind_api(g_api, 0, 0);
eglDestroySurface(g_egl_dpy, g_egl_surf);
}
@@ -310,7 +310,7 @@ static void gfx_ctx_destroy(void)
eglBindAPI(EGL_OPENVG_API);
eglMakeCurrent(g_egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- gfx_ctx_bind_api(g_api);
+ gfx_ctx_bind_api(g_api, 0, 0);
eglMakeCurrent(g_egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglTerminate(g_egl_dpy);
}
@@ -405,7 +405,7 @@ static bool gfx_ctx_init_egl_image_buffer(const video_info_t *video)
goto fail;
}
- gfx_ctx_bind_api(g_api);
+ gfx_ctx_bind_api(g_api, 0, 0);
eglMakeCurrent(g_egl_dpy, g_egl_surf, g_egl_surf, g_egl_ctx);
g_smooth = video->smooth;
@@ -424,7 +424,7 @@ fail:
g_pbuff_surf = EGL_NO_CONTEXT;
}
- gfx_ctx_bind_api(g_api);
+ gfx_ctx_bind_api(g_api, 0, 0);
eglMakeCurrent(g_egl_dpy, g_egl_surf, g_egl_surf, g_egl_ctx);
return false;
@@ -453,7 +453,7 @@ static bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned
vgImageSubData(g_egl_vgimage[index], frame, pitch, (rgb32 ? VG_sXRGB_8888 : VG_sRGB_565), 0, 0, width, height);
*image_handle = eglBuffer[index];
- gfx_ctx_bind_api(g_api);
+ gfx_ctx_bind_api(g_api, 0, 0);
eglMakeCurrent(g_egl_dpy, g_egl_surf, g_egl_surf, g_egl_ctx);
return ret;
diff --git a/gfx/context/wgl_ctx.c b/gfx/context/wgl_ctx.c
index b0d70cdc58..e8667ff66e 100644
--- a/gfx/context/wgl_ctx.c
+++ b/gfx/context/wgl_ctx.c
@@ -104,7 +104,15 @@ static void create_gl_context(HWND hwnd)
return;
}
- if (g_major * 1000 + g_minor >= 3001) // Create core context
+#ifdef GL_DEBUG
+ bool debug = true;
+#else
+ bool debug = g_extern.system.hw_render_callback.debug_context;
+#endif
+
+ bool core_context = (g_major * 1000 + g_minor) >= 3001;
+
+ if (core_context || debug)
{
#ifndef WGL_CONTEXT_MAJOR_VERSION_ARB
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
@@ -124,13 +132,26 @@ static void create_gl_context(HWND hwnd)
#ifndef WGL_CONTEXT_DEBUG_BIT_ARB
#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001
#endif
- const int attribs[] = {
- WGL_CONTEXT_MAJOR_VERSION_ARB, (int)g_major,
- WGL_CONTEXT_MINOR_VERSION_ARB, (int)g_minor,
- WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
- WGL_CONTEXT_FLAGS_ARB, g_extern.system.hw_render_callback.debug_context ? WGL_CONTEXT_DEBUG_BIT_ARB : 0,
- 0,
- };
+ int attribs[16];
+ int *aptr = attribs;
+
+ if (core_context)
+ {
+ *aptr++ = WGL_CONTEXT_MAJOR_VERSION_ARB;
+ *aptr++ = g_major;
+ *aptr++ = WGL_CONTEXT_MINOR_VERSION_ARB;
+ *aptr++ = g_minor;
+ *aptr++ = WGL_CONTEXT_PROFILE_MASK_ARB;
+ *aptr++ = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
+ }
+
+ if (debug)
+ {
+ *aptr++ = WGL_CONTEXT_FLAGS_ARB;
+ *aptr++ = WGL_CONTEXT_DEBUG_BIT_ARB;
+ }
+
+ *aptr = 0;
if (!pcreate_context)
pcreate_context = (wglCreateContextAttribsProc)wglGetProcAddress("wglCreateContextAttribsARB");
@@ -448,14 +469,16 @@ static bool gfx_ctx_set_video_mode(
if (!g_hwnd)
goto error;
+#ifdef HAVE_WIN32GUI
if (!fullscreen)
{
SetMenu(g_hwnd, LoadMenu(GetModuleHandle(NULL), MAKEINTRESOURCE(IDR_MENU)));
- RECT rcTemp = {0, 0, g_resize_height, 0x7FFF}; // 0x7FFF="Infinite" height
+ RECT rcTemp = {0, 0, width, 0x7FFF}; // 0x7FFF = "Infinite" height
SendMessage(g_hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rcTemp); // recalculate margin, taking possible menu wrap into account
- g_resize_height += rcTemp.top + rect.top; // extend by new top margin and substract previous margin
- SetWindowPos(g_hwnd, NULL, 0, 0, g_resize_width, g_resize_height, SWP_NOMOVE);
+ unsigned menu_height = rcTemp.top + rect.top; // rect.top is negative after AdjustWindowRect().
+ SetWindowPos(g_hwnd, NULL, 0, 0, width, height + menu_height, SWP_NOMOVE);
}
+#endif
if (!fullscreen || windowed_full)
{
diff --git a/gfx/d3d9/d3d9.cpp b/gfx/d3d9/d3d9.cpp
index c4de8cf9c1..608a676dba 100644
--- a/gfx/d3d9/d3d9.cpp
+++ b/gfx/d3d9/d3d9.cpp
@@ -145,7 +145,20 @@ void D3DVideo::make_d3dpp(const video_info_t &info, D3DPRESENT_PARAMETERS &d3dpp
d3dpp.Windowed = g_settings.video.windowed_fullscreen || !info.fullscreen;
- d3dpp.PresentationInterval = info.vsync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE;
+ if (info.vsync)
+ {
+ switch (g_settings.video.swap_interval)
+ {
+ default:
+ case 1: d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; break;
+ case 2: d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_TWO; break;
+ case 3: d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_THREE; break;
+ case 4: d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_FOUR; break;
+ }
+ }
+ else
+ d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
+
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.BackBufferCount = 2;
@@ -350,17 +363,17 @@ void D3DVideo::calculate_rect(unsigned width, unsigned height,
else
{
float device_aspect = static_cast(width) / static_cast(height);
- if (fabs(device_aspect - desired_aspect) < 0.0001)
+ if (fabsf(device_aspect - desired_aspect) < 0.0001f)
set_viewport(0, 0, width, height);
else if (device_aspect > desired_aspect)
{
- float delta = (desired_aspect / device_aspect - 1.0) / 2.0 + 0.5;
- set_viewport(width * (0.5 - delta), 0, 2.0 * width * delta, height);
+ float delta = (desired_aspect / device_aspect - 1.0f) / 2.0f + 0.5f;
+ set_viewport(int(roundf(width * (0.5f - delta))), 0, unsigned(roundf(2.0f * width * delta)), height);
}
else
{
- float delta = (device_aspect / desired_aspect - 1.0) / 2.0 + 0.5;
- set_viewport(0, height * (0.5 - delta), width, 2.0 * height * delta);
+ float delta = (device_aspect / desired_aspect - 1.0f) / 2.0f + 0.5f;
+ set_viewport(0, int(roundf(height * (0.5f - delta))), width, unsigned(roundf(2.0f * height * delta)));
}
}
}
@@ -614,6 +627,17 @@ bool D3DVideo::frame(const void *frame,
dev->SetViewport(&screen_vp);
dev->Clear(0, 0, D3DCLEAR_TARGET, 0, 1, 0);
+ // Insert black frame first, so we can screenshot, etc.
+ if (g_settings.video.black_frame_insertion)
+ {
+ if (dev->Present(nullptr, nullptr, nullptr, nullptr) != D3D_OK)
+ {
+ needs_restore = true;
+ return true;
+ }
+ dev->Clear(0, 0, D3DCLEAR_TARGET, 0, 1, 0);
+ }
+
if (!chain->render(frame, width, height, pitch, rotation))
{
RARCH_ERR("[D3D9]: Failed to render scene.\n");
diff --git a/gfx/fonts/gl_raster_font.c b/gfx/fonts/gl_raster_font.c
index 644184e20e..657ad4a96c 100644
--- a/gfx/fonts/gl_raster_font.c
+++ b/gfx/fonts/gl_raster_font.c
@@ -35,6 +35,7 @@ static bool gl_init_font(void *data, const char *font_path, float font_size)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]);
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &gl->max_font_size);
}
else
{
@@ -124,6 +125,11 @@ static void adjust_power_of_two(gl_t *gl, struct font_rect *geom)
geom->pot_width = next_pow2(geom->width);
geom->pot_height = next_pow2(geom->height);
+ if (geom->pot_width > gl->max_font_size)
+ geom->pot_width = gl->max_font_size;
+ if (geom->pot_height > gl->max_font_size)
+ geom->pot_height = gl->max_font_size;
+
if ((geom->pot_width > gl->font_tex_w) || (geom->pot_height > gl->font_tex_h))
{
gl->font_tex_buf = (uint32_t*)realloc(gl->font_tex_buf,
diff --git a/gfx/gfx_context.c b/gfx/gfx_context.c
index 4d5c45c30e..67d771d665 100644
--- a/gfx/gfx_context.c
+++ b/gfx/gfx_context.c
@@ -13,6 +13,7 @@
* If not, see .
*/
+#include "../general.h"
#include "gfx_context.h"
#include "../general.h"
#include
@@ -52,6 +53,9 @@ static const gfx_ctx_driver_t *gfx_ctx_drivers[] = {
#if defined(IOS) || defined(OSX) //< Don't use __APPLE__ as it breaks basic SDL builds
&gfx_ctx_apple,
#endif
+#ifdef EMSCRIPTEN
+ &gfx_ctx_emscripten,
+#endif
};
const gfx_ctx_driver_t *gfx_ctx_find_driver(const char *ident)
diff --git a/gfx/gfx_context.h b/gfx/gfx_context.h
index c8614799a5..da5c682792 100644
--- a/gfx/gfx_context.h
+++ b/gfx/gfx_context.h
@@ -108,6 +108,7 @@ extern const gfx_ctx_driver_t gfx_ctx_wgl;
extern const gfx_ctx_driver_t gfx_ctx_videocore;
extern const gfx_ctx_driver_t gfx_ctx_bbqnx;
extern const gfx_ctx_driver_t gfx_ctx_apple;
+extern const gfx_ctx_driver_t gfx_ctx_emscripten;
extern const gfx_ctx_driver_t gfx_ctx_null;
const gfx_ctx_driver_t *gfx_ctx_find_driver(const char *ident); // Finds driver with ident. Does not initialize.
diff --git a/gfx/gl.c b/gfx/gl.c
index 628f743634..e9975a7589 100644
--- a/gfx/gl.c
+++ b/gfx/gl.c
@@ -23,6 +23,7 @@
#include "../performance.h"
#include "scaler/scaler.h"
#include "image.h"
+#include "../file.h"
#include
#include "../libretro.h"
@@ -152,7 +153,7 @@ static bool check_sync_proc(gl_t *gl)
#ifndef HAVE_OPENGLES
static bool init_vao(gl_t *gl)
{
- if (!gl_query_extension(gl, "ARB_vertex_array_object"))
+ if (!gl->core_context && !gl_query_extension(gl, "ARB_vertex_array_object"))
return false;
bool present = glGenVertexArrays && glBindVertexArray && glDeleteVertexArrays;
@@ -183,7 +184,7 @@ static bool init_vao(gl_t *gl)
#elif !defined(HAVE_OPENGLES2)
static bool check_fbo_proc(gl_t *gl)
{
- if (!gl_query_extension(gl, "ARB_framebuffer_object"))
+ if (!gl->core_context && !gl_query_extension(gl, "ARB_framebuffer_object"))
return false;
return glGenFramebuffers && glBindFramebuffer && glFramebufferTexture2D &&
@@ -346,6 +347,7 @@ void gl_shader_set_coords(void *data, const struct gl_coords *coords, const math
#define gl_shader_num(gl) ((gl->shader) ? gl->shader->num_shaders() : 0)
#define gl_shader_filter_type(gl, index, smooth) ((gl->shader) ? gl->shader->filter_type(index, smooth) : false)
+#define gl_shader_wrap_type(gl, index) ((gl->shader) ? gl->shader->wrap_type(index) : RARCH_WRAP_BORDER)
#ifdef IOS
// There is no default frame buffer on IOS.
@@ -464,16 +466,18 @@ static void gl_create_fbo_textures(void *data)
{
glBindTexture(GL_TEXTURE_2D, gl->fbo_texture[i]);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gl->border_type);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gl->border_type);
-
GLuint filter_type = base_filt;
bool smooth = false;
if (gl_shader_filter_type(gl, i + 2, &smooth))
filter_type = smooth ? GL_LINEAR : GL_NEAREST;
+ enum gfx_wrap_type wrap = gl_shader_wrap_type(gl, i + 2);
+ GLenum wrap_enum = gl_wrap_type_to_enum(wrap);
+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter_type);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter_type);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_enum);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_enum);
bool fp_fbo = gl->fbo_scale[i].valid && gl->fbo_scale[i].fp_fbo;
@@ -779,22 +783,22 @@ void gl_set_viewport(void *data, unsigned width, unsigned height, bool force_ful
else
#endif
{
- if (fabs(device_aspect - desired_aspect) < 0.0001)
+ if (fabsf(device_aspect - desired_aspect) < 0.0001f)
{
// If the aspect ratios of screen and desired aspect ratio are sufficiently equal (floating point stuff),
// assume they are actually equal.
}
else if (device_aspect > desired_aspect)
{
- delta = (desired_aspect / device_aspect - 1.0) / 2.0 + 0.5;
- x = (unsigned)(width * (0.5 - delta));
- width = (unsigned)(2.0 * width * delta);
+ delta = (desired_aspect / device_aspect - 1.0f) / 2.0f + 0.5f;
+ x = (int)roundf(width * (0.5f - delta));
+ width = (unsigned)roundf(2.0f * width * delta);
}
else
{
- delta = (device_aspect / desired_aspect - 1.0) / 2.0 + 0.5;
- y = (unsigned)(height * (0.5 - delta));
- height = (unsigned)(2.0 * height * delta);
+ delta = (device_aspect / desired_aspect - 1.0f) / 2.0f + 0.5f;
+ y = (int)roundf(height * (0.5f - delta));
+ height = (unsigned)roundf(2.0f * height * delta);
}
}
@@ -1155,8 +1159,8 @@ static void gl_init_textures(void *data, const video_info_t *video)
{
glBindTexture(GL_TEXTURE_2D, gl->texture[i]);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gl->border_type);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gl->border_type);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gl->wrap_mode);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gl->wrap_mode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl->tex_filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl->tex_filter);
@@ -1398,18 +1402,7 @@ static bool gl_frame(void *data, const void *frame, unsigned width, unsigned hei
glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]);
#ifdef HAVE_FBO
- // Data is already on GPU :) Have to reset some state however incase core changed it.
- if (gl->hw_render_fbo_init)
- {
- gl_update_input_size(gl, width, height, pitch, false);
-
- if (!gl->fbo_inited)
- {
- gl_bind_backbuffer();
- gl_set_viewport(gl, gl->win_width, gl->win_height, false, true);
- }
- }
- else
+ if (!gl->hw_render_fbo_init)
#endif
{
gl_update_input_size(gl, width, height, pitch, true);
@@ -1426,6 +1419,13 @@ static bool gl_frame(void *data, const void *frame, unsigned width, unsigned hei
#ifdef HAVE_FBO
if (gl->hw_render_fbo_init)
{
+ gl_update_input_size(gl, width, height, pitch, false);
+ if (!gl->fbo_inited)
+ {
+ gl_bind_backbuffer();
+ gl_set_viewport(gl, gl->win_width, gl->win_height, false, true);
+ }
+
#ifndef HAVE_OPENGLES
if (!gl->core_context)
glEnable(GL_TEXTURE_2D);
@@ -1450,6 +1450,11 @@ static bool gl_frame(void *data, const void *frame, unsigned width, unsigned hei
memcpy(tex_info.coord, gl->tex_coords, sizeof(gl->tex_coords));
glClear(GL_COLOR_BUFFER_BIT);
+ if (g_settings.video.black_frame_insertion)
+ {
+ context_swap_buffers_func();
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
if (gl->shader)
gl->shader->set_params(width, height,
@@ -1619,7 +1624,7 @@ static void gl_set_nonblock_state(void *data, bool state)
gl_t *gl = (gl_t*)data;
(void)gl;
- context_swap_interval_func(state ? 0 : 1);
+ context_swap_interval_func(state ? 0 : g_settings.video.swap_interval);
}
static bool resolve_extensions(gl_t *gl)
@@ -1642,13 +1647,6 @@ static bool resolve_extensions(gl_t *gl)
RARCH_LOG("[GL]: Using ARB_sync to reduce latency.\n");
#endif
-#ifdef NO_GL_CLAMP_TO_BORDER
- // NOTE: This will be a serious problem for some shaders.
- gl->border_type = GL_CLAMP_TO_EDGE;
-#else
- gl->border_type = GL_CLAMP_TO_BORDER;
-#endif
-
driver.gfx_use_rgba = false;
#ifdef HAVE_OPENGLES2
if (gl_query_extension(gl, "BGRA8888"))
@@ -1661,11 +1659,33 @@ static bool resolve_extensions(gl_t *gl)
}
#endif
-#if 0
- // Useful for debugging, but kinda obnoxious.
- const char *ext = (const char*)glGetString(GL_EXTENSIONS);
- if (ext)
- RARCH_LOG("[GL] Supported extensions: %s\n", ext);
+#ifdef GL_DEBUG
+ // Useful for debugging, but kinda obnoxious otherwise.
+ RARCH_LOG("[GL]: Supported extensions:\n");
+ if (gl->core_context)
+ {
+#ifdef GL_NUM_EXTENSIONS
+ GLint exts = 0;
+ glGetIntegerv(GL_NUM_EXTENSIONS, &exts);
+ for (GLint i = 0; i < exts; i++)
+ {
+ const char *ext = (const char*)glGetStringi(GL_EXTENSIONS, i);
+ if (ext)
+ RARCH_LOG("\t%s\n", ext);
+ }
+#endif
+ }
+ else
+ {
+ const char *ext = (const char*)glGetString(GL_EXTENSIONS);
+ if (ext)
+ {
+ struct string_list *list = string_split(ext, " ");
+ for (size_t i = 0; i < list->size; i++)
+ RARCH_LOG("\t%s\n", list->elems[i].data);
+ string_list_free(list);
+ }
+ }
#endif
return true;
@@ -1814,6 +1834,84 @@ static const gfx_ctx_driver_t *gl_get_context(void)
return gfx_ctx_init_first(api, major, minor);
}
+#ifdef GL_DEBUG
+#ifdef HAVE_OPENGLES2
+#define DEBUG_CALLBACK_TYPE GL_APIENTRY
+#else
+#define DEBUG_CALLBACK_TYPE APIENTRY
+#endif
+static void DEBUG_CALLBACK_TYPE gl_debug_cb(GLenum source, GLenum type,
+ GLuint id, GLenum severity, GLsizei length,
+ const GLchar *message, void *userParam)
+{
+ (void)id;
+ (void)length;
+
+ gl_t *gl = (gl_t*)userParam; // Useful for debugger.
+ (void)gl;
+
+ const char *src;
+ switch (source)
+ {
+ case GL_DEBUG_SOURCE_API: src = "API"; break;
+ case GL_DEBUG_SOURCE_WINDOW_SYSTEM: src = "Window system"; break;
+ case GL_DEBUG_SOURCE_SHADER_COMPILER: src = "Shader compiler"; break;
+ case GL_DEBUG_SOURCE_THIRD_PARTY: src = "3rd party"; break;
+ case GL_DEBUG_SOURCE_APPLICATION: src = "Application"; break;
+ case GL_DEBUG_SOURCE_OTHER: src = "Other"; break;
+ default: src = "Unknown"; break;
+ }
+
+ const char *typestr;
+ switch (type)
+ {
+ case GL_DEBUG_TYPE_ERROR: typestr = "Error"; break;
+ case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: typestr = "Deprecated behavior"; break;
+ case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: typestr = "Undefined behavior"; break;
+ case GL_DEBUG_TYPE_PORTABILITY: typestr = "Portability"; break;
+ case GL_DEBUG_TYPE_PERFORMANCE: typestr = "Performance"; break;
+ case GL_DEBUG_TYPE_MARKER: typestr = "Marker"; break;
+ case GL_DEBUG_TYPE_PUSH_GROUP: typestr = "Push group"; break;
+ case GL_DEBUG_TYPE_POP_GROUP: typestr = "Pop group"; break;
+ case GL_DEBUG_TYPE_OTHER: typestr = "Other"; break;
+ default: typestr = "Unknown"; break;
+ }
+
+ switch (severity)
+ {
+ case GL_DEBUG_SEVERITY_HIGH:
+ RARCH_ERR("[GL debug (High, %s, %s)]: %s\n", src, typestr, message);
+ break;
+ case GL_DEBUG_SEVERITY_MEDIUM:
+ RARCH_WARN("[GL debug (Medium, %s, %s)]: %s\n", src, typestr, message);
+ break;
+ case GL_DEBUG_SEVERITY_LOW:
+ RARCH_LOG("[GL debug (Low, %s, %s)]: %s\n", src, typestr, message);
+ break;
+ }
+}
+
+static void gl_begin_debug(gl_t *gl)
+{
+ if (gl_query_extension(gl, "KHR_debug"))
+ {
+ glDebugMessageCallback(gl_debug_cb, gl);
+ glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
+ glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
+ }
+#ifndef HAVE_OPENGLES2
+ else if (gl_query_extension(gl, "ARB_debug_output"))
+ {
+ glDebugMessageCallbackARB(gl_debug_cb, gl);
+ glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
+ glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
+ }
+#endif
+ else
+ RARCH_ERR("Neither GL_KHR_debug nor GL_ARB_debug_output are implemented. Cannot start GL debugging.\n");
+}
+#endif
+
static void *gl_init(const video_info_t *video, const input_driver_t **input, void **input_data)
{
#ifdef _WIN32
@@ -1848,7 +1946,7 @@ static void *gl_init(const video_info_t *video, const input_driver_t **input, vo
context_get_video_size_func(&gl->full_x, &gl->full_y);
RARCH_LOG("Detecting screen resolution %ux%u.\n", gl->full_x, gl->full_y);
- context_swap_interval_func(video->vsync ? 1 : 0);
+ context_swap_interval_func(video->vsync ? g_settings.video.swap_interval : 0);
unsigned win_width = video->width;
unsigned win_height = video->height;
@@ -1864,10 +1962,15 @@ static void *gl_init(const video_info_t *video, const input_driver_t **input, vo
return NULL;
}
+ glGetError(); // Clear out potential error flags incase we use cached context.
+
const char *vendor = (const char*)glGetString(GL_VENDOR);
const char *renderer = (const char*)glGetString(GL_RENDERER);
RARCH_LOG("[GL]: Vendor: %s, Renderer: %s.\n", vendor, renderer);
+ const char *version = (const char*)glGetString(GL_VERSION);
+ RARCH_LOG("[GL]: Version: %s.\n", version);
+
#ifndef RARCH_CONSOLE
rglgen_resolve_symbols(gl->ctx_driver->get_proc_address);
#endif
@@ -1881,6 +1984,10 @@ static void *gl_init(const video_info_t *video, const input_driver_t **input, vo
return NULL;
}
+#ifdef GL_DEBUG
+ gl_begin_debug(gl);
+#endif
+
gl->vsync = video->vsync;
gl->fullscreen = video->fullscreen;
@@ -1948,6 +2055,7 @@ static void *gl_init(const video_info_t *video, const input_driver_t **input, vo
gl->tex_filter = force_smooth ? GL_LINEAR : GL_NEAREST;
else
gl->tex_filter = video->smooth ? GL_LINEAR : GL_NEAREST;
+ gl->wrap_mode = gl_wrap_type_to_enum(gl_shader_wrap_type(gl, 1));
gl_set_texture_fmts(gl, video->rgb32);
@@ -2048,18 +2156,22 @@ static void gl_update_tex_filter_frame(gl_t *gl)
bool smooth = false;
if (!gl_shader_filter_type(gl, 1, &smooth))
smooth = g_settings.video.smooth;
+ GLenum wrap_mode = gl_wrap_type_to_enum(gl_shader_wrap_type(gl, 1));
gl->video_info.smooth = smooth;
GLuint new_filt = smooth ? GL_LINEAR : GL_NEAREST;
- if (new_filt == gl->tex_filter)
+ if (new_filt == gl->tex_filter && wrap_mode == gl->wrap_mode)
return;
gl->tex_filter = new_filt;
+ gl->wrap_mode = wrap_mode;
for (unsigned i = 0; i < gl->textures; i++)
{
if (gl->texture[i])
{
glBindTexture(GL_TEXTURE_2D, gl->texture[i]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gl->wrap_mode);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gl->wrap_mode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl->tex_filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl->tex_filter);
}
@@ -2179,6 +2291,12 @@ static bool gl_read_viewport(void *data, uint8_t *buffer)
RARCH_PERFORMANCE_INIT(read_viewport);
RARCH_PERFORMANCE_START(read_viewport);
+#ifdef HAVE_FBO
+ // Make sure we're reading from backbuffer incase some state has been overridden.
+ if (gl->hw_render_fbo_init || gl->fbo_inited)
+ gl_bind_backbuffer();
+#endif
+
#ifdef HAVE_OPENGLES
glPixelStorei(GL_PACK_ALIGNMENT, get_alignment(gl->vp.width * 3));
// GLES doesn't support glReadBuffer ... Take a chance that it'll work out right.
@@ -2287,8 +2405,8 @@ static bool gl_overlay_load(void *data, const uint32_t *image, unsigned width, u
glGenTextures(1, &gl->tex_overlay);
glBindTexture(GL_TEXTURE_2D, gl->tex_overlay);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gl->border_type);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gl->border_type);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -2460,8 +2578,8 @@ static void gl_set_texture_frame(void *data,
{
glGenTextures(1, &gl->rgui_texture);
glBindTexture(GL_TEXTURE_2D, gl->rgui_texture);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gl->border_type);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gl->border_type);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
diff --git a/gfx/gl_common.h b/gfx/gl_common.h
index 3da0b5d53c..1d5f308d92 100644
--- a/gfx/gl_common.h
+++ b/gfx/gl_common.h
@@ -199,7 +199,7 @@ typedef struct gl
GLenum internal_fmt;
GLenum texture_type; // RGB565 or ARGB
GLenum texture_fmt;
- GLenum border_type;
+ GLenum wrap_mode;
unsigned base_size; // 2 or 4
// Fonts
@@ -207,6 +207,7 @@ typedef struct gl
const gl_font_renderer_t *font_ctx;
const font_renderer_driver_t *font_driver;
GLuint font_tex;
+ GLint max_font_size;
int font_tex_w, font_tex_h;
uint32_t *font_tex_buf;
char font_last_msg[256];
@@ -314,5 +315,26 @@ void gl_shader_set_coords(void *data, const struct gl_coords *coords, const math
void gl_init_fbo(void *data, unsigned width, unsigned height);
void gl_deinit_fbo(void *data);
+static inline GLenum gl_wrap_type_to_enum(enum gfx_wrap_type type)
+{
+ switch (type)
+ {
+#ifndef HAVE_OPENGLES
+ case RARCH_WRAP_BORDER:
+ return GL_CLAMP_TO_BORDER;
+#else
+ case RARCH_WRAP_BORDER:
+#endif
+ case RARCH_WRAP_EDGE:
+ return GL_CLAMP_TO_EDGE;
+ case RARCH_WRAP_REPEAT:
+ return GL_REPEAT;
+ case RARCH_WRAP_MIRRORED_REPEAT:
+ return GL_MIRRORED_REPEAT;
+ default:
+ return 0;
+ }
+}
+
#endif
diff --git a/gfx/shader_cg.c b/gfx/shader_cg.c
index a634d99253..7f00885b20 100644
--- a/gfx/shader_cg.c
+++ b/gfx/shader_cg.c
@@ -493,18 +493,12 @@ static bool load_plain(const char *path)
#define print_buf(buf, ...) snprintf(buf, sizeof(buf), __VA_ARGS__)
-#ifdef HAVE_OPENGLES2
-#define BORDER_FUNC GL_CLAMP_TO_EDGE
-#else
-#define BORDER_FUNC GL_CLAMP_TO_BORDER
-#endif
-
-static void load_texture_data(GLuint obj, const struct texture_image *img, bool smooth)
+static void load_texture_data(GLuint obj, const struct texture_image *img, bool smooth, GLenum wrap)
{
glBindTexture(GL_TEXTURE_2D, obj);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, BORDER_FUNC);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, BORDER_FUNC);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, smooth ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, smooth ? GL_LINEAR : GL_NEAREST);
@@ -538,7 +532,8 @@ static bool load_textures(void)
}
load_texture_data(lut_textures[i], &img,
- cg_shader->lut[i].filter != RARCH_FILTER_NEAREST);
+ cg_shader->lut[i].filter != RARCH_FILTER_NEAREST,
+ gl_wrap_type_to_enum(cg_shader->lut[i].wrap));
}
glBindTexture(GL_TEXTURE_2D, 0);
@@ -903,6 +898,14 @@ static bool gl_cg_filter_type(unsigned index, bool *smooth)
return false;
}
+static enum gfx_wrap_type gl_cg_wrap_type(unsigned index)
+{
+ if (cg_active && index)
+ return cg_shader->pass[index - 1].wrap;
+ else
+ return RARCH_WRAP_BORDER;
+}
+
static void gl_cg_shader_scale(unsigned index, struct gfx_fbo_scale *scale)
{
if (cg_active && index)
@@ -942,6 +945,7 @@ const gl_shader_backend_t gl_cg_backend = {
gl_cg_use,
gl_cg_num,
gl_cg_filter_type,
+ gl_cg_wrap_type,
gl_cg_shader_scale,
gl_cg_set_coords,
gl_cg_set_mvp,
diff --git a/gfx/shader_common.h b/gfx/shader_common.h
index 2b72da2bed..dae07b2608 100644
--- a/gfx/shader_common.h
+++ b/gfx/shader_common.h
@@ -47,6 +47,7 @@ struct gl_shader_backend
void (*use)(unsigned index);
unsigned (*num_shaders)(void);
bool (*filter_type)(unsigned index, bool *smooth);
+ enum gfx_wrap_type (*wrap_type)(unsigned index);
void (*shader_scale)(unsigned index, struct gfx_fbo_scale *scale);
bool (*set_coords)(const struct gl_coords *coords);
bool (*set_mvp)(const math_matrix *mat);
diff --git a/gfx/shader_glsl.c b/gfx/shader_glsl.c
index a15d2ef0e5..06c25ca322 100644
--- a/gfx/shader_glsl.c
+++ b/gfx/shader_glsl.c
@@ -1180,6 +1180,14 @@ static bool gl_glsl_filter_type(unsigned index, bool *smooth)
return false;
}
+static enum gfx_wrap_type gl_glsl_wrap_type(unsigned index)
+{
+ if (glsl_enable && index)
+ return glsl_shader->pass[index - 1].wrap;
+ else
+ return RARCH_WRAP_BORDER;
+}
+
static void gl_glsl_shader_scale(unsigned index, struct gfx_fbo_scale *scale)
{
if (glsl_enable && index)
@@ -1221,6 +1229,7 @@ const gl_shader_backend_t gl_glsl_backend = {
gl_glsl_use,
gl_glsl_num,
gl_glsl_filter_type,
+ gl_glsl_wrap_type,
gl_glsl_shader_scale,
gl_glsl_set_coords,
gl_glsl_set_mvp,
diff --git a/gfx/shader_parse.c b/gfx/shader_parse.c
index 4ac92499ea..b92d68b8a7 100644
--- a/gfx/shader_parse.c
+++ b/gfx/shader_parse.c
@@ -30,6 +30,41 @@
#define print_buf(buf, ...) snprintf(buf, sizeof(buf), __VA_ARGS__)
+static const char *wrap_mode_to_str(enum gfx_wrap_type type)
+{
+ switch (type)
+ {
+ case RARCH_WRAP_BORDER:
+ return "clamp_to_border";
+ case RARCH_WRAP_EDGE:
+ return "clamp_to_edge";
+ case RARCH_WRAP_REPEAT:
+ return "repeat";
+ case RARCH_WRAP_MIRRORED_REPEAT:
+ return "mirrored_repeat";
+ default:
+ return "???";
+ }
+}
+
+static enum gfx_wrap_type wrap_str_to_mode(const char *wrap_mode)
+{
+ if (strcmp(wrap_mode, "clamp_to_border") == 0)
+ return RARCH_WRAP_BORDER;
+ else if (strcmp(wrap_mode, "clamp_to_edge") == 0)
+ return RARCH_WRAP_EDGE;
+ else if (strcmp(wrap_mode, "repeat") == 0)
+ return RARCH_WRAP_REPEAT;
+ else if (strcmp(wrap_mode, "mirrored_repeat") == 0)
+ return RARCH_WRAP_MIRRORED_REPEAT;
+ else
+ {
+ RARCH_WARN("Invalid wrapping type %s. Valid ones are: clamp_to_border (default), clamp_to_edge, repeat and mirrored_repeat. Falling back to default.\n",
+ wrap_mode);
+ return RARCH_WRAP_DEFAULT;
+ }
+}
+
// CGP
static bool shader_parse_pass(config_file_t *conf, struct gfx_shader_pass *pass, unsigned i)
{
@@ -52,6 +87,13 @@ static bool shader_parse_pass(config_file_t *conf, struct gfx_shader_pass *pass,
else
pass->filter = RARCH_FILTER_UNSPEC;
+ // Wrapping mode
+ char wrap_name_buf[64];
+ print_buf(wrap_name_buf, "wrap_mode%u", i);
+ char wrap_mode[64];
+ if (config_get_array(conf, wrap_name_buf, wrap_mode, sizeof(wrap_mode)))
+ pass->wrap = wrap_str_to_mode(wrap_mode);
+
// Frame count mod
char frame_count_mod[64] = {0};
char frame_count_mod_buf[64];
@@ -207,6 +249,12 @@ static bool shader_parse_textures(config_file_t *conf, struct gfx_shader *shader
shader->lut[shader->luts].filter = smooth ? RARCH_FILTER_LINEAR : RARCH_FILTER_NEAREST;
else
shader->lut[shader->luts].filter = RARCH_FILTER_UNSPEC;
+
+ char id_wrap[64];
+ print_buf(id_wrap, "%s_wrap_mode", id);
+ char wrap_mode[64];
+ if (config_get_array(conf, id_wrap, wrap_mode, sizeof(wrap_mode)))
+ shader->lut[shader->luts].wrap = wrap_str_to_mode(wrap_mode);
}
return true;
@@ -998,6 +1046,9 @@ void gfx_shader_write_conf_cgp(config_file_t *conf, const struct gfx_shader *sha
config_set_bool(conf, key, pass->filter == RARCH_FILTER_LINEAR);
}
+ print_buf(key, "wrap_mode%u", i);
+ config_set_string(conf, key, wrap_mode_to_str(pass->wrap));
+
if (pass->frame_count_mod)
{
print_buf(key, "frame_count_mod%u", i);
@@ -1031,6 +1082,9 @@ void gfx_shader_write_conf_cgp(config_file_t *conf, const struct gfx_shader *sha
print_buf(key, "%s_linear", shader->lut[i].id);
config_set_bool(conf, key, shader->lut[i].filter != RARCH_FILTER_LINEAR);
}
+
+ print_buf(key, "%s_wrap_mode", shader->lut[i].id);
+ config_set_string(conf, key, wrap_mode_to_str(shader->lut[i].wrap));
}
}
diff --git a/gfx/shader_parse.h b/gfx/shader_parse.h
index dcbda69b20..0822dc7c41 100644
--- a/gfx/shader_parse.h
+++ b/gfx/shader_parse.h
@@ -40,7 +40,16 @@ enum gfx_filter_type
{
RARCH_FILTER_UNSPEC = 0,
RARCH_FILTER_LINEAR,
- RARCH_FILTER_NEAREST,
+ RARCH_FILTER_NEAREST
+};
+
+enum gfx_wrap_type
+{
+ RARCH_WRAP_BORDER = 0, // Kinda deprecated, but keep as default. Will be translated to EDGE in GLES.
+ RARCH_WRAP_DEFAULT = RARCH_WRAP_BORDER,
+ RARCH_WRAP_EDGE,
+ RARCH_WRAP_REPEAT,
+ RARCH_WRAP_MIRRORED_REPEAT
};
struct gfx_fbo_scale
@@ -69,6 +78,7 @@ struct gfx_shader_pass
struct gfx_fbo_scale fbo;
enum gfx_filter_type filter;
+ enum gfx_wrap_type wrap;
unsigned frame_count_mod;
};
@@ -77,6 +87,7 @@ struct gfx_shader_lut
char id[64];
char path[PATH_MAX];
enum gfx_filter_type filter;
+ enum gfx_wrap_type wrap;
};
// This is pretty big, shouldn't be put on the stack.
diff --git a/gfx/vg.c b/gfx/vg.c
index bbfc3a8264..1297cf4063 100644
--- a/gfx/vg.c
+++ b/gfx/vg.c
@@ -87,7 +87,7 @@ static void *vg_init(const video_info_t *video, const input_driver_t **input, vo
if (!vg)
return NULL;
- vg->driver = gfx_ctx_init_first(GFX_CTX_OPENVG_API);
+ vg->driver = gfx_ctx_init_first(GFX_CTX_OPENVG_API, 0, 0);
if (!vg->driver)
{
diff --git a/griffin/griffin.c b/griffin/griffin.c
index cbb9cc1f0e..5ff04b6ea9 100644
--- a/griffin/griffin.c
+++ b/griffin/griffin.c
@@ -298,8 +298,8 @@ INPUT
#include "../android/native/jni/input_autodetect.c"
#include "../android/native/jni/input_android.c"
#elif defined(IOS) || defined(OSX)
-#include "../apple/RetroArch/apple_input.c"
-#include "../apple/RetroArch/apple_joypad.c"
+#include "../apple/common/apple_input.c"
+#include "../apple/common/apple_joypad.c"
#elif defined(__BLACKBERRY_QNX__)
#include "../blackberry-qnx/qnx_input.c"
#endif
diff --git a/input/autoconf/builtin.h b/input/autoconf/builtin.h
new file mode 100644
index 0000000000..be4d9f1d4e
--- /dev/null
+++ b/input/autoconf/builtin.h
@@ -0,0 +1,24 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2013 - pinumbernumber
+ *
+ * RetroArch is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with RetroArch.
+ * If not, see .
+ */
+
+#ifndef AUTOCONF_BUILTIN_H__
+#define AUTOCONF_BUILTIN_H__
+
+#include "../input_common.h"
+#define DECL_BTN(btn, bind) "input_" #btn "_btn = " #bind "\n"
+#define DECL_AXIS(axis, bind) "input_" #axis "_axis = " #bind "\n"
+
+#endif
+
diff --git a/input/autoconf/builtin_win.c b/input/autoconf/builtin_win.c
new file mode 100644
index 0000000000..d28e9de1df
--- /dev/null
+++ b/input/autoconf/builtin_win.c
@@ -0,0 +1,92 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2013 - pinumbernumber
+ *
+ * RetroArch is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with RetroArch.
+ * If not, see .
+ */
+
+#include "builtin.h"
+
+#define XINPUT_DEFAULT_BINDS \
+DECL_BTN(a, 1) \
+DECL_BTN(b, 0) \
+DECL_BTN(x, 3) \
+DECL_BTN(y, 2) \
+DECL_BTN(start, 6) \
+DECL_BTN(select, 7) \
+DECL_BTN(up, h0up) \
+DECL_BTN(down, h0down) \
+DECL_BTN(left, h0left) \
+DECL_BTN(right, h0right) \
+DECL_BTN(l, 4) \
+DECL_BTN(r, 5) \
+DECL_BTN(l3, 8) \
+DECL_BTN(r3, 9) \
+DECL_BTN(menu_toggle, 10) \
+DECL_AXIS(l2, +4) \
+DECL_AXIS(r2, +5) \
+DECL_AXIS(l_x_plus, +0) \
+DECL_AXIS(l_x_minus, -0) \
+DECL_AXIS(l_y_plus, -1) \
+DECL_AXIS(l_y_minus, +1) \
+DECL_AXIS(r_x_plus, +2) \
+DECL_AXIS(r_x_minus, -2) \
+DECL_AXIS(r_y_plus, -3) \
+DECL_AXIS(r_y_minus, +3)
+
+// Some hardcoded autoconfig information. Will be used for pads with no autoconfig cfg files.
+const char* const input_builtin_autoconfs[] =
+{
+ "input_device = \"XInput Controller (Player 1)\" \n"
+ "input_driver = \"winxinput\" \n"
+ XINPUT_DEFAULT_BINDS,
+
+ "input_device = \"XInput Controller (Player 2)\" \n"
+ "input_driver = \"winxinput\" \n"
+ XINPUT_DEFAULT_BINDS,
+
+ "input_device = \"XInput Controller (Player 3)\" \n"
+ "input_driver = \"winxinput\" \n"
+ XINPUT_DEFAULT_BINDS,
+
+ "input_device = \"XInput Controller (Player 4)\" \n"
+ "input_driver = \"winxinput\" \n"
+ XINPUT_DEFAULT_BINDS,
+
+ "input_device = \"Dual Trigger 3-in-1\" \n"
+ "input_driver = \"dinput\" \n"
+ DECL_BTN(a, 2)
+ DECL_BTN(b, 1)
+ DECL_BTN(x, 3)
+ DECL_BTN(y, 0)
+ DECL_BTN(start, 9)
+ DECL_BTN(select, 8)
+ DECL_BTN(up, h0up)
+ DECL_BTN(down, h0down)
+ DECL_BTN(left, h0left)
+ DECL_BTN(right, h0right)
+ DECL_BTN(l, 4)
+ DECL_BTN(r, 5)
+ DECL_BTN(l2, 6)
+ DECL_BTN(r2, 7)
+ DECL_BTN(l3, 10)
+ DECL_BTN(r3, 11)
+ DECL_AXIS(l_x_plus, +0)
+ DECL_AXIS(l_x_minus, -0)
+ DECL_AXIS(l_y_plus, +1)
+ DECL_AXIS(l_y_minus, -1)
+ DECL_AXIS(r_x_plus, +2)
+ DECL_AXIS(r_x_minus, -2)
+ DECL_AXIS(r_y_plus, +5)
+ DECL_AXIS(r_y_minus, -5),
+
+ NULL
+};
diff --git a/input/dinput.c b/input/dinput.c
index 024f323ba9..2639970c28 100644
--- a/input/dinput.c
+++ b/input/dinput.c
@@ -49,6 +49,7 @@ struct dinput_joypad
{
LPDIRECTINPUTDEVICE8 joypad;
DIJOYSTATE2 joy_state;
+ char* joy_name;
};
static unsigned g_joypad_cnt;
@@ -68,12 +69,6 @@ static bool dinput_init_context(void)
if (g_ctx)
return true;
- if (driver.display_type != RARCH_DISPLAY_WIN32)
- {
- RARCH_ERR("Cannot open DInput as no Win32 window is present.\n");
- return false;
- }
-
CoInitialize(NULL);
// Who said we shouldn't have same call signature in a COM API? <_<
@@ -351,6 +346,12 @@ const input_driver_t input_dinput = {
dinput_grab_mouse,
};
+// Keep track of which pad indexes are 360 controllers
+// not static, will be read in winxinput_joypad.c
+// -1 = not xbox pad, otherwise 0..3
+int g_xinput_pad_indexes[MAX_PLAYERS];
+bool g_xinput_block_pads;
+
static void dinput_joypad_destroy(void)
{
for (unsigned i = 0; i < MAX_PLAYERS; i++)
@@ -360,6 +361,10 @@ static void dinput_joypad_destroy(void)
IDirectInputDevice8_Unacquire(g_pads[i].joypad);
IDirectInputDevice8_Release(g_pads[i].joypad);
}
+
+ free(g_pads[i].joy_name);
+ g_pads[i].joy_name = NULL;
+
}
g_joypad_cnt = 0;
@@ -386,6 +391,53 @@ static BOOL CALLBACK enum_axes_cb(const DIDEVICEOBJECTINSTANCE *inst, void *p)
return DIENUM_CONTINUE;
}
+// TODO: Use a better way of detecting dual XInput/DInput pads. This current method
+// will not work correctly for third-party controllers or future MS pads (Xbox One?).
+// An example of this is provided in the DX SDK, which advises "Enum each PNP device
+// using WMI and check each device ID to see if it contains "IG_"". Unfortunately the
+// example code is a horrible unsightly mess.
+static const char* const XINPUT_PAD_NAMES[] =
+{
+ "XBOX 360 For Windows",
+ "Controller (Gamepad for Xbox 360)",
+ "Controller (XBOX 360 For Windows)",
+ "Controller (Xbox 360 Wireless Receiver for Windows)",
+ "Controller (Xbox wireless receiver for windows)",
+ "XBOX 360 For Windows (Controller)",
+ "Xbox 360 Wireless Receiver",
+ "Xbox 360 Wireless Controller",
+ "Xbox Receiver for Windows (Wireless Controller)",
+ "Xbox wireless receiver for windows (Controller)",
+ "Gamepad F310 (Controller)",
+ "Controller (Gamepad F310)",
+ "Wireless Gamepad F710 (Controller)",
+ "Controller (Batarang wired controller (XBOX))",
+ "Afterglow Gamepad for Xbox 360 (Controller)"
+ "Controller (Rumble Gamepad F510)",
+ "Controller (Wireless Gamepad F710)",
+ "Controller (Xbox 360 Wireless Receiver for Windows)",
+ "Controller (Xbox wireless receiver for windows)",
+ "Controller (XBOX360 GAMEPAD)",
+ "MadCatz GamePad",
+ NULL
+};
+
+static bool name_is_xinput_pad(const char* name)
+{
+ for (unsigned i = 0; ; ++i)
+ {
+ const char* t = XINPUT_PAD_NAMES[i];
+ if (t == NULL)
+ return false;
+ else if (strcasecmp(name, t) == 0)
+ return true;
+ }
+}
+
+// Forward declaration
+static const char *dinput_joypad_name(unsigned pad);
+static unsigned g_last_xinput_pad_index;
+
static BOOL CALLBACK enum_joypad_cb(const DIDEVICEINSTANCE *inst, void *p)
{
(void)p;
@@ -399,7 +451,20 @@ static BOOL CALLBACK enum_joypad_cb(const DIDEVICEINSTANCE *inst, void *p)
#else
if (FAILED(IDirectInput8_CreateDevice(g_ctx, &inst->guidInstance, pad, NULL)))
#endif
- return DIENUM_CONTINUE;
+ return DIENUM_CONTINUE;
+
+ g_pads[g_joypad_cnt].joy_name = strdup(inst->tszProductName);
+
+#ifdef HAVE_WINXINPUT
+ bool is_xinput_pad = g_xinput_block_pads && name_is_xinput_pad(inst->tszProductName);
+
+ if (is_xinput_pad)
+ {
+ if (g_last_xinput_pad_index < 4)
+ g_xinput_pad_indexes[g_joypad_cnt] = g_last_xinput_pad_index++;
+ goto enum_iteration_done;
+ }
+#endif
IDirectInputDevice8_SetDataFormat(*pad, &c_dfDIJoystick2);
IDirectInputDevice8_SetCooperativeLevel(*pad, (HWND)driver.video_window,
@@ -407,9 +472,17 @@ static BOOL CALLBACK enum_joypad_cb(const DIDEVICEINSTANCE *inst, void *p)
IDirectInputDevice8_EnumObjects(*pad, enum_axes_cb,
*pad, DIDFT_ABSAXIS);
+
+#ifdef HAVE_WINXINPUT
+ if (!is_xinput_pad)
+#endif
+ {
+ strlcpy(g_settings.input.device_names[g_joypad_cnt], dinput_joypad_name(g_joypad_cnt), sizeof(g_settings.input.device_names[g_joypad_cnt]));
+ input_config_autoconfigure_joypad(g_joypad_cnt, dinput_joypad_name(g_joypad_cnt), dinput_joypad.ident);
+ }
+enum_iteration_done:
g_joypad_cnt++;
-
return DIENUM_CONTINUE;
}
@@ -417,6 +490,14 @@ static bool dinput_joypad_init(void)
{
if (!dinput_init_context())
return false;
+
+ g_last_xinput_pad_index = 0;
+
+ for (unsigned i = 0; i < MAX_PLAYERS; ++i)
+ {
+ g_xinput_pad_indexes[i] = -1;
+ g_pads[i].joy_name = NULL;
+ }
RARCH_LOG("Enumerating DInput joypads ...\n");
IDirectInput8_EnumDevices(g_ctx, DI8DEVCLASS_GAMECTRL,
@@ -524,7 +605,7 @@ static void dinput_joypad_poll(void)
{
struct dinput_joypad *pad = &g_pads[i];
- if (pad->joypad)
+ if (pad->joypad && g_xinput_pad_indexes[i] < 0)
{
memset(&pad->joy_state, 0, sizeof(pad->joy_state));
@@ -557,8 +638,9 @@ static bool dinput_joypad_query_pad(unsigned pad)
static const char *dinput_joypad_name(unsigned pad)
{
- (void)pad;
- // FIXME
+ if (pad < MAX_PLAYERS)
+ return g_pads[pad].joy_name;
+
return NULL;
}
diff --git a/input/input_common.c b/input/input_common.c
index 12be6eaf76..0e7418bfb8 100644
--- a/input/input_common.c
+++ b/input/input_common.c
@@ -16,6 +16,7 @@
#include "input_common.h"
#include
#include
+#include
#include "../general.h"
#include "../driver.h"
@@ -41,6 +42,9 @@
static const rarch_joypad_driver_t *joypad_drivers[] = {
#ifndef IS_RETROLAUNCH
+#ifdef HAVE_WINXINPUT
+ &winxinput_joypad,
+#endif
#ifdef HAVE_DINPUT
&dinput_joypad,
#endif
@@ -512,6 +516,96 @@ const struct rarch_key_map rarch_key_map_dinput[] = {
};
#endif
+#ifdef EMSCRIPTEN
+const struct rarch_key_map rarch_key_map_rwebinput[] = {
+ { 37, RETROK_LEFT },
+ { 39, RETROK_RIGHT },
+ { 38, RETROK_UP },
+ { 40, RETROK_DOWN },
+ { 13, RETROK_RETURN },
+ { 9, RETROK_TAB },
+ { 45, RETROK_INSERT },
+ { 46, RETROK_DELETE },
+ { 16, RETROK_RSHIFT },
+ { 16, RETROK_LSHIFT },
+ { 17, RETROK_LCTRL },
+ { 35, RETROK_END },
+ { 36, RETROK_HOME },
+ { 34, RETROK_PAGEDOWN },
+ { 33, RETROK_PAGEUP },
+ { 18, RETROK_LALT },
+ { 32, RETROK_SPACE },
+ { 27, RETROK_ESCAPE },
+ { 8, RETROK_BACKSPACE },
+ { 13, RETROK_KP_ENTER },
+ { 107, RETROK_KP_PLUS },
+ { 109, RETROK_KP_MINUS },
+ { 106, RETROK_KP_MULTIPLY },
+ { 111, RETROK_KP_DIVIDE },
+ { 192, RETROK_BACKQUOTE },
+ { 19, RETROK_PAUSE },
+ { 96, RETROK_KP0 },
+ { 97, RETROK_KP1 },
+ { 98, RETROK_KP2 },
+ { 99, RETROK_KP3 },
+ { 100, RETROK_KP4 },
+ { 101, RETROK_KP5 },
+ { 102, RETROK_KP6 },
+ { 103, RETROK_KP7 },
+ { 104, RETROK_KP8 },
+ { 105, RETROK_KP9 },
+ { 48, RETROK_0 },
+ { 49, RETROK_1 },
+ { 50, RETROK_2 },
+ { 51, RETROK_3 },
+ { 52, RETROK_4 },
+ { 53, RETROK_5 },
+ { 54, RETROK_6 },
+ { 55, RETROK_7 },
+ { 56, RETROK_8 },
+ { 57, RETROK_9 },
+ { 112, RETROK_F1 },
+ { 113, RETROK_F2 },
+ { 114, RETROK_F3 },
+ { 115, RETROK_F4 },
+ { 116, RETROK_F5 },
+ { 117, RETROK_F6 },
+ { 118, RETROK_F7 },
+ { 119, RETROK_F8 },
+ { 120, RETROK_F9 },
+ { 121, RETROK_F10 },
+ { 122, RETROK_F11 },
+ { 123, RETROK_F12 },
+ { 65, RETROK_a },
+ { 66, RETROK_b },
+ { 67, RETROK_c },
+ { 68, RETROK_d },
+ { 69, RETROK_e },
+ { 70, RETROK_f },
+ { 71, RETROK_g },
+ { 72, RETROK_h },
+ { 73, RETROK_i },
+ { 74, RETROK_j },
+ { 75, RETROK_k },
+ { 76, RETROK_l },
+ { 77, RETROK_m },
+ { 78, RETROK_n },
+ { 79, RETROK_o },
+ { 80, RETROK_p },
+ { 81, RETROK_q },
+ { 82, RETROK_r },
+ { 83, RETROK_s },
+ { 84, RETROK_t },
+ { 85, RETROK_u },
+ { 86, RETROK_v },
+ { 87, RETROK_w },
+ { 88, RETROK_x },
+ { 89, RETROK_y },
+ { 90, RETROK_z },
+ { 0, RETROK_UNKNOWN },
+};
+#endif
+
static enum retro_key rarch_keysym_lut[RETROK_LAST];
void input_init_keyboard_lut(const struct rarch_key_map *map)
@@ -807,6 +901,38 @@ static void input_autoconfigure_joypad_conf(config_file_t *conf, struct retro_ke
}
}
+static bool input_try_autoconfigure_joypad_from_conf(config_file_t *conf, unsigned index, const char *name, const char *driver, bool block_osd_spam)
+{
+ if (!conf)
+ return false;
+
+ char ident[1024];
+ char input_driver[1024];
+
+ *ident = *input_driver = '\0';
+
+ config_get_array(conf, "input_device", ident, sizeof(ident));
+ config_get_array(conf, "input_driver", input_driver, sizeof(input_driver));
+
+ if (!strcmp(ident, name) && !strcmp(driver, input_driver))
+ {
+ g_settings.input.autoconfigured[index] = true;
+ input_autoconfigure_joypad_conf(conf, g_settings.input.autoconf_binds[index]);
+
+ char msg[512];
+ snprintf(msg, sizeof(msg), "Joypad port #%u (%s) configured.",
+ index, name);
+
+ if (!block_osd_spam)
+ msg_queue_push(g_extern.msg_queue, msg, 0, 60);
+ RARCH_LOG("%s\n", msg);
+
+ return true;
+ }
+
+ return false;
+}
+
void input_config_autoconfigure_joypad(unsigned index, const char *name, const char *driver)
{
if (!g_settings.input.autodetect_enable)
@@ -826,47 +952,41 @@ void input_config_autoconfigure_joypad(unsigned index, const char *name, const c
if (!name)
return;
- if (!*g_settings.input.autoconfig_dir)
- return;
+ // false = load from both cfg files and internal
+ bool internal_only = !*g_settings.input.autoconfig_dir;
- struct string_list *list = dir_list_new(g_settings.input.autoconfig_dir, "cfg", false);
- if (!list)
- return;
-
- char ident[1024];
- char input_driver[1024];
- for (size_t i = 0; i < list->size; i++)
+#ifdef HAVE_BUILTIN_AUTOCONFIG
+ // First internal
+ for (size_t i = 0; input_builtin_autoconfs[i]; i++)
{
- *ident = *input_driver = '\0';
-
- config_file_t *conf = config_file_new(list->elems[i].data);
- if (!conf)
- continue;
-
- config_get_array(conf, "input_device", ident, sizeof(ident));
- config_get_array(conf, "input_driver", input_driver, sizeof(input_driver));
-
- if (!strcmp(ident, name) && !strcmp(driver, input_driver))
- {
- g_settings.input.autoconfigured[index] = true;
- input_autoconfigure_joypad_conf(conf, g_settings.input.autoconf_binds[index]);
-
- char msg[512];
- snprintf(msg, sizeof(msg), "Joypad port #%u (%s) configured.",
- index, name);
-
- if (!block_osd_spam)
- msg_queue_push(g_extern.msg_queue, msg, 0, 60);
- RARCH_LOG("%s\n", msg);
-
- config_file_free(conf);
+ config_file_t *conf = config_file_new_from_string(input_builtin_autoconfs[i]);
+ bool success = input_try_autoconfigure_joypad_from_conf(conf, index, name, driver, block_osd_spam);
+ config_file_free(conf);
+ if (success)
break;
- }
- else
- config_file_free(conf);
}
-
- string_list_free(list);
+#endif
+
+ // Now try files
+ if (!internal_only)
+ {
+ struct string_list *list = dir_list_new(g_settings.input.autoconfig_dir, "cfg", false);
+ if (!list)
+ return;
+
+ for (size_t i = 0; i < list->size; i++)
+ {
+ config_file_t *conf = config_file_new(list->elems[i].data);
+ if (!conf)
+ continue;
+ bool success = input_try_autoconfigure_joypad_from_conf(conf, index, name, driver, block_osd_spam);
+ config_file_free(conf);
+ if (success)
+ break;
+ }
+
+ string_list_free(list);
+ }
}
#else
void input_config_autoconfigure_joypad(unsigned index, const char *name, const char *driver)
diff --git a/input/input_common.h b/input/input_common.h
index 2ce912e98a..96d641dbdc 100644
--- a/input/input_common.h
+++ b/input/input_common.h
@@ -93,6 +93,7 @@ const char *input_joypad_name(const rarch_joypad_driver_t *driver, unsigned joyp
extern const rarch_joypad_driver_t dinput_joypad;
extern const rarch_joypad_driver_t linuxraw_joypad;
+extern const rarch_joypad_driver_t winxinput_joypad; // Named as such to avoid confusion with xb1/360 port code
extern const rarch_joypad_driver_t sdl_joypad;
@@ -105,6 +106,7 @@ struct rarch_key_map
extern const struct rarch_key_map rarch_key_map_x11[];
extern const struct rarch_key_map rarch_key_map_sdl[];
extern const struct rarch_key_map rarch_key_map_dinput[];
+extern const struct rarch_key_map rarch_key_map_rwebinput[];
void input_init_keyboard_lut(const struct rarch_key_map *map);
enum retro_key input_translate_keysym_to_rk(unsigned sym);
@@ -134,6 +136,8 @@ struct input_key_map
};
extern const struct input_key_map input_config_key_map[];
+extern const char* const input_builtin_autoconfs[];
+
const char *input_config_get_prefix(unsigned player, bool meta);
void input_config_parse_key(config_file_t *conf, const char *prefix, const char *btn,
diff --git a/input/overlay.c b/input/overlay.c
index 9696fa5767..3854ea11a0 100644
--- a/input/overlay.c
+++ b/input/overlay.c
@@ -31,6 +31,13 @@ enum overlay_hitbox
OVERLAY_HITBOX_RECT
};
+enum overlay_type
+{
+ OVERLAY_TYPE_BUTTONS = 0,
+ OVERLAY_TYPE_ANALOG_LEFT,
+ OVERLAY_TYPE_ANALOG_RIGHT
+};
+
struct overlay_desc
{
float x;
@@ -39,7 +46,9 @@ struct overlay_desc
enum overlay_hitbox hitbox;
float range_x, range_y;
+ enum overlay_type type;
uint64_t key_mask;
+ float analog_saturate_pct;
unsigned next_index;
char next_index_name[64];
@@ -234,14 +243,23 @@ static bool input_overlay_load_desc(config_file_t *conf, struct overlay_desc *de
char *key = list->elems[0].data;
char *save;
desc->key_mask = 0;
- for (const char *tmp = strtok_r(key, "|", &save); tmp; tmp = strtok_r(NULL, "|", &save))
- desc->key_mask |= UINT64_C(1) << input_str_to_bind(tmp);
- if (desc->key_mask & (UINT64_C(1) << RARCH_OVERLAY_NEXT))
+ if (strcmp(key, "analog_left") == 0)
+ desc->type = OVERLAY_TYPE_ANALOG_LEFT;
+ else if (strcmp(key, "analog_right") == 0)
+ desc->type = OVERLAY_TYPE_ANALOG_RIGHT;
+ else
{
- char overlay_target_key[64];
- snprintf(overlay_target_key, sizeof(overlay_target_key), "overlay%u_desc%u_next_target", ol_index, desc_index);
- config_get_array(conf, overlay_target_key, desc->next_index_name, sizeof(desc->next_index_name));
+ desc->type = OVERLAY_TYPE_BUTTONS;
+ for (const char *tmp = strtok_r(key, "|", &save); tmp; tmp = strtok_r(NULL, "|", &save))
+ desc->key_mask |= UINT64_C(1) << input_str_to_bind(tmp);
+
+ if (desc->key_mask & (UINT64_C(1) << RARCH_OVERLAY_NEXT))
+ {
+ char overlay_target_key[64];
+ snprintf(overlay_target_key, sizeof(overlay_target_key), "overlay%u_desc%u_next_target", ol_index, desc_index);
+ config_get_array(conf, overlay_target_key, desc->next_index_name, sizeof(desc->next_index_name));
+ }
}
desc->x = strtod(x, NULL) / width;
@@ -258,6 +276,21 @@ static bool input_overlay_load_desc(config_file_t *conf, struct overlay_desc *de
goto end;
}
+ if (desc->type != OVERLAY_TYPE_BUTTONS)
+ {
+ if (desc->hitbox != OVERLAY_HITBOX_RADIAL)
+ {
+ RARCH_ERR("[Overlay]: Analog hitbox type must be \"radial\".\n");
+ ret = false;
+ goto end;
+ }
+
+ char overlay_analog_saturate_key[64];
+ snprintf(overlay_analog_saturate_key, sizeof(overlay_analog_saturate_key), "overlay%u_desc%u_saturate_pct", ol_index, desc_index);
+ if (!config_get_float(conf, overlay_analog_saturate_key, &desc->analog_saturate_pct))
+ desc->analog_saturate_pct = 1.0f;
+ }
+
desc->range_x = strtod(list->elems[4].data, NULL) / width;
desc->range_y = strtod(list->elems[5].data, NULL) / height;
@@ -530,12 +563,14 @@ static bool inside_hitbox(const struct overlay_desc *desc, float x, float y)
}
}
-uint64_t input_overlay_poll(input_overlay_t *ol, int16_t norm_x, int16_t norm_y)
+void input_overlay_poll(input_overlay_t *ol, input_overlay_state_t *out, int16_t norm_x, int16_t norm_y)
{
+ memset(out, 0, sizeof(*out));
+
if (!ol->enable)
{
ol->blocked = false;
- return 0;
+ return;
}
// norm_x and norm_y is in [-0x7fff, 0x7fff] range, like RETRO_DEVICE_POINTER.
@@ -547,25 +582,40 @@ uint64_t input_overlay_poll(input_overlay_t *ol, int16_t norm_x, int16_t norm_y)
x /= ol->active->mod_w;
y /= ol->active->mod_h;
- uint64_t state = 0;
for (size_t i = 0; i < ol->active->size; i++)
{
- if (inside_hitbox(&ol->active->descs[i], x, y))
+ if (!inside_hitbox(&ol->active->descs[i], x, y))
+ continue;
+
+ if (ol->active->descs[i].type == OVERLAY_TYPE_BUTTONS)
{
uint64_t mask = ol->active->descs[i].key_mask;
- state |= mask;
+ out->buttons |= mask;
if (mask & (UINT64_C(1) << RARCH_OVERLAY_NEXT))
ol->next_index = ol->active->descs[i].next_index;
}
+ else
+ {
+ float x_val = (x - ol->active->descs[i].x) / ol->active->descs[i].range_x / ol->active->descs[i].analog_saturate_pct;
+ float y_val = (y - ol->active->descs[i].y) / ol->active->descs[i].range_y / ol->active->descs[i].analog_saturate_pct;
+
+ if (fabs(x_val) > 1.0f)
+ x_val = (x_val > 0.0f) ? 1.0f : -1.0f;
+
+ if (fabs(y_val) > 1.0f)
+ y_val = (y_val > 0.0f) ? 1.0f : -1.0f;
+
+ unsigned int base = (ol->active->descs[i].type == OVERLAY_TYPE_ANALOG_RIGHT) ? 2 : 0;
+ out->analog[base + 0] = x_val * 32767.0f;
+ out->analog[base + 1] = y_val * 32767.0f;
+ }
}
- if (!state)
+ if (!out->buttons)
ol->blocked = false;
else if (ol->blocked)
- state = 0;
-
- return state;
+ memset(out, 0, sizeof(*out));
}
void input_overlay_poll_clear(input_overlay_t *ol)
diff --git a/input/overlay.h b/input/overlay.h
index c5f08491cb..399cb896cf 100644
--- a/input/overlay.h
+++ b/input/overlay.h
@@ -30,6 +30,12 @@ extern "C" {
// This interface requires that the video driver has support for the overlay interface.
typedef struct input_overlay input_overlay_t;
+typedef struct input_overlay_state
+{
+ uint64_t buttons; // This is a bitmask of (1 << key_bind_id).
+ int16_t analog[4]; // Left X, Left Y, Right X, Right Y
+} input_overlay_state_t;
+
input_overlay_t *input_overlay_new(const char *overlay);
void input_overlay_free(input_overlay_t *ol);
@@ -38,8 +44,7 @@ void input_overlay_enable(input_overlay_t *ol, bool enable);
bool input_overlay_full_screen(input_overlay_t *ol);
// norm_x and norm_y are the result of input_translate_coord_viewport().
-// Resulting state is a bitmask of (1 << key_bind_id).
-uint64_t input_overlay_poll(input_overlay_t *ol, int16_t norm_x, int16_t norm_y);
+void input_overlay_poll(input_overlay_t *ol, input_overlay_state_t *out, int16_t norm_x, int16_t norm_y);
// Call when there is nothing to poll. Allows overlay to clear certain state.
void input_overlay_poll_clear(input_overlay_t *ol);
diff --git a/input/rwebinput_input.c b/input/rwebinput_input.c
new file mode 100644
index 0000000000..1a65eec7d3
--- /dev/null
+++ b/input/rwebinput_input.c
@@ -0,0 +1,149 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2010-2013 - Michael Lelli
+ *
+ * RetroArch is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with RetroArch.
+ * If not, see .
+ */
+
+#include "input_common.h"
+
+#include "../driver.h"
+
+#include "../boolean.h"
+#include "../general.h"
+
+#include "../emscripten/RWebInput.h"
+
+static bool uninited = false;
+
+typedef struct rwebinput_input
+{
+ rwebinput_state_t state;
+ int context;
+} rwebinput_input_t;
+
+static void *rwebinput_input_init(void)
+{
+ rwebinput_input_t *rwebinput = (rwebinput_input_t*)calloc(1, sizeof(*rwebinput));
+ if (!rwebinput)
+ return NULL;
+
+ rwebinput->context = RWebInputInit();
+ if (!rwebinput->context)
+ {
+ free(rwebinput);
+ return NULL;
+ }
+
+ input_init_keyboard_lut(rarch_key_map_rwebinput);
+
+ return rwebinput;
+}
+
+static bool rwebinput_key_pressed(rwebinput_input_t *rwebinput, int key)
+{
+ if (key >= RETROK_LAST)
+ return false;
+
+ unsigned sym = input_translate_rk_to_keysym((enum retro_key)key);
+ bool ret = rwebinput->state.keys[sym >> 3] & (1 << (sym & 7));
+ return ret;
+}
+
+static bool rwebinput_is_pressed(rwebinput_input_t *rwebinput, const struct retro_keybind *binds, unsigned id)
+{
+ if (id < RARCH_BIND_LIST_END)
+ {
+ const struct retro_keybind *bind = &binds[id];
+ return bind->valid && rwebinput_key_pressed(rwebinput, binds[id].key);
+ }
+ else
+ return false;
+}
+
+static bool rwebinput_bind_button_pressed(void *data, int key)
+{
+ rwebinput_input_t *rwebinput = (rwebinput_input_t*)data;
+ return rwebinput_is_pressed(rwebinput, g_settings.input.binds[0], key);
+}
+
+static int16_t rwebinput_mouse_state(rwebinput_input_t *rwebinput, unsigned id)
+{
+ switch (id)
+ {
+ case RETRO_DEVICE_ID_MOUSE_X:
+ return (int16_t) rwebinput->state.mouse_x;
+ case RETRO_DEVICE_ID_MOUSE_Y:
+ return (int16_t) rwebinput->state.mouse_y;
+ case RETRO_DEVICE_ID_MOUSE_LEFT:
+ return rwebinput->state.mouse_l;
+ case RETRO_DEVICE_ID_MOUSE_RIGHT:
+ return rwebinput->state.mouse_r;
+ default:
+ return 0;
+ }
+}
+
+static int16_t rwebinput_input_state(void *data, const struct retro_keybind **binds, unsigned port, unsigned device, unsigned index, unsigned id)
+{
+ rwebinput_input_t *rwebinput = (rwebinput_input_t*)data;
+
+ switch (device)
+ {
+ case RETRO_DEVICE_JOYPAD:
+ return rwebinput_is_pressed(rwebinput, binds[port], id);
+
+ case RETRO_DEVICE_KEYBOARD:
+ return rwebinput_key_pressed(rwebinput, id);
+
+ case RETRO_DEVICE_MOUSE:
+ return rwebinput_mouse_state(rwebinput, id);
+
+ default:
+ return 0;
+ }
+}
+
+static void rwebinput_input_free(void *data)
+{
+ rwebinput_input_t *rwebinput = (rwebinput_input_t*)data;
+ uninited = true;
+
+ RWebInputDestroy(rwebinput->context);
+
+ free(data);
+}
+
+static void rwebinput_input_poll(void *data)
+{
+ rwebinput_input_t *rwebinput = (rwebinput_input_t*)data;
+
+ rwebinput_state_t *state = RWebInputPoll(rwebinput->context);
+ memcpy(&rwebinput->state, state, sizeof(rwebinput->state));
+}
+
+static void rwebinput_grab_mouse(void *data, bool state)
+{
+ (void)data;
+ (void)state;
+}
+
+const input_driver_t input_rwebinput = {
+ rwebinput_input_init,
+ rwebinput_input_poll,
+ rwebinput_input_state,
+ rwebinput_bind_button_pressed,
+ rwebinput_input_free,
+ NULL,
+ "rwebinput",
+ rwebinput_grab_mouse,
+};
+
diff --git a/input/winxinput_joypad.c b/input/winxinput_joypad.c
new file mode 100644
index 0000000000..bc9f419df0
--- /dev/null
+++ b/input/winxinput_joypad.c
@@ -0,0 +1,376 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2013 - pinumbernumber
+ *
+ * RetroArch is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with RetroArch.
+ * If not, see .
+ */
+
+// Support 360 controllers on Windows.
+// Said controllers do show under DInput but they have limitations in this mode;
+// The triggers are combined rather than seperate and it is not possible to use
+// the guide button.
+
+// Some wrappers for other controllers also simulate xinput (as it is easier to implement)
+// so this may be useful for those also.
+#include "input_common.h"
+
+#include "../general.h"
+#include "../boolean.h"
+
+#include
+#include
+#include
+
+// Check the definitions do not already exist.
+// Official and mingw xinput headers have different include guards
+#if ((!_XINPUT_H_) && (!__WINE_XINPUT_H))
+
+#define XINPUT_GAMEPAD_DPAD_UP 0x0001
+#define XINPUT_GAMEPAD_DPAD_DOWN 0x0002
+#define XINPUT_GAMEPAD_DPAD_LEFT 0x0004
+#define XINPUT_GAMEPAD_DPAD_RIGHT 0x0008
+#define XINPUT_GAMEPAD_START 0x0010
+#define XINPUT_GAMEPAD_BACK 0x0020
+#define XINPUT_GAMEPAD_LEFT_THUMB 0x0040
+#define XINPUT_GAMEPAD_RIGHT_THUMB 0x0080
+#define XINPUT_GAMEPAD_LEFT_SHOULDER 0x0100
+#define XINPUT_GAMEPAD_RIGHT_SHOULDER 0x0200
+#define XINPUT_GAMEPAD_A 0x1000
+#define XINPUT_GAMEPAD_B 0x2000
+#define XINPUT_GAMEPAD_X 0x4000
+#define XINPUT_GAMEPAD_Y 0x8000
+
+typedef struct
+{
+ uint16_t wButtons;
+ uint8_t bLeftTrigger;
+ uint8_t bRightTrigger;
+ int16_t sThumbLX;
+ int16_t sThumbLY;
+ int16_t sThumbRX;
+ int16_t sThumbRY;
+} XINPUT_GAMEPAD;
+
+typedef struct
+{
+ uint32_t dwPacketNumber;
+ XINPUT_GAMEPAD Gamepad;
+} XINPUT_STATE;
+
+#endif
+
+// Guide constant is not officially documented
+#define XINPUT_GAMEPAD_GUIDE 0x0400
+
+#ifndef ERROR_DEVICE_NOT_CONNECTED
+#define ERROR_DEVICE_NOT_CONNECTED 1167
+#endif
+
+#ifndef HAVE_DINPUT
+#error Cannot compile xinput without dinput.
+#endif
+
+// Due to 360 pads showing up under both XI and DI, and since we are going
+// to have to pass through unhandled joypad numbers to DI, a slightly ugly
+// hack is required here. dinput_joypad_init will fill this.
+// For each pad index, the appropriate entry will be set to -1 if it is not
+// a 360 pad, or the correct XInput player number (0..3 inclusive) if it is.
+extern int g_xinput_pad_indexes[MAX_PLAYERS];
+extern bool g_xinput_block_pads;
+
+// For xinput1_3.dll
+static HINSTANCE g_winxinput_dll;
+
+// Function pointer, to be assigned with GetProcAddress
+typedef uint32_t (__stdcall *XInputGetStateEx_t)(uint32_t, XINPUT_STATE*);
+static XInputGetStateEx_t g_XInputGetStateEx;
+
+// Guide button may or may not be available
+static bool g_winxinput_guide_button_supported;
+
+typedef struct
+{
+ XINPUT_STATE xstate;
+ bool connected;
+} winxinput_joypad_state;
+
+static winxinput_joypad_state g_winxinput_states[4];
+
+static inline int pad_index_to_xplayer_index(unsigned pad)
+{
+ return g_xinput_pad_indexes[pad];
+}
+
+// Generic "XInput" instead of "Xbox 360", because there are
+// some other non-xbox third party PC controllers.
+static const char* const XBOX_CONTROLLER_NAMES[4] =
+{
+ "XInput Controller (Player 1)",
+ "XInput Controller (Player 2)",
+ "XInput Controller (Player 3)",
+ "XInput Controller (Player 4)"
+};
+
+const char* winxinput_joypad_name (unsigned pad)
+{
+ int xplayer = pad_index_to_xplayer_index(pad);
+
+ if (xplayer < 0)
+ return dinput_joypad.name(pad);
+ else
+ // TODO: Different name if disconnected?
+ return XBOX_CONTROLLER_NAMES[xplayer];
+}
+
+
+
+static bool winxinput_joypad_init(void)
+{
+ g_winxinput_dll = NULL;
+
+ // Find the correct path to load the DLL from.
+ // Usually this will be from the system directory,
+ // but occasionally a user may wish to use a third-party
+ // wrapper DLL (such as x360ce); support these by checking
+ // the working directory first.
+
+ // No need to check for existance as we will be checking LoadLibrary's
+ // success anyway.
+
+ const char *version = "1.4";
+ g_winxinput_dll = LoadLibrary("xinput1_4.dll"); // Using dylib_* complicates building joyconfig.
+ if (!g_winxinput_dll)
+ {
+ g_winxinput_dll = LoadLibrary("xinput1_3.dll");
+ version = "1.3";
+ }
+
+ if (!g_winxinput_dll)
+ {
+ RARCH_ERR("Failed to load XInput, ensure DirectX and controller drivers are up to date.\n");
+ return false;
+ }
+
+ RARCH_LOG("Found XInput v%s.\n", version);
+
+ // If we get here then an xinput DLL is correctly loaded.
+ // First try to load ordinal 100 (XInputGetStateEx).
+ g_XInputGetStateEx = (XInputGetStateEx_t) GetProcAddress(g_winxinput_dll, (const char*)100);
+ g_winxinput_guide_button_supported = true;
+
+ if (!g_XInputGetStateEx)
+ {
+ // no ordinal 100. (Presumably a wrapper.) Load the ordinary
+ // XInputGetState, at the cost of losing guide button support.
+ g_winxinput_guide_button_supported = false;
+ g_XInputGetStateEx = (XInputGetStateEx_t) GetProcAddress(g_winxinput_dll, "XInputGetState");
+ if (!g_XInputGetStateEx)
+ {
+ RARCH_ERR("Failed to init XInput: xinput1_3.dll is invalid or corrupt.\n");
+ return false; // DLL was loaded but did not contain the correct function.
+ }
+ RARCH_WARN("XInput: No guide button support.\n");
+ }
+
+ // Zero out the states
+ for (unsigned i = 0; i < 4; ++i)
+ memset(&g_winxinput_states[i], 0, sizeof(winxinput_joypad_state));
+
+ // Do a dummy poll to check which controllers are connected.
+ XINPUT_STATE dummy_state;
+ for (unsigned i = 0; i < 4; ++i)
+ {
+ g_winxinput_states[i].connected = !(g_XInputGetStateEx(i, &dummy_state) == ERROR_DEVICE_NOT_CONNECTED);
+ if (g_winxinput_states[i].connected)
+ RARCH_LOG("Found XInput controller, player #%u\n", i);
+ }
+
+ if ((!g_winxinput_states[0].connected) &&
+ (!g_winxinput_states[1].connected) &&
+ (!g_winxinput_states[2].connected) &&
+ (!g_winxinput_states[3].connected))
+ return false;
+
+ g_xinput_block_pads = true;
+
+ // We're going to have to be buddies with dinput if we want to be able
+ // to use XI and non-XI controllers together.
+ if (!dinput_joypad.init())
+ {
+ g_xinput_block_pads = false;
+ return false;
+ }
+
+ for (unsigned autoconf_pad = 0; autoconf_pad < MAX_PLAYERS; autoconf_pad++)
+ {
+ if (pad_index_to_xplayer_index(autoconf_pad) > -1)
+ {
+ strlcpy(g_settings.input.device_names[autoconf_pad], winxinput_joypad_name(autoconf_pad), sizeof(g_settings.input.device_names[autoconf_pad]));
+ input_config_autoconfigure_joypad(autoconf_pad, winxinput_joypad_name(autoconf_pad), winxinput_joypad.ident);
+ }
+ }
+
+ return true;
+
+}
+
+static bool winxinput_joypad_query_pad(unsigned pad)
+{
+ int xplayer = pad_index_to_xplayer_index(pad);
+ if (xplayer > -1)
+ return g_winxinput_states[xplayer].connected;
+ else
+ return dinput_joypad.query_pad(pad);
+}
+
+static void winxinput_joypad_destroy(void)
+{
+ for (unsigned i = 0; i < 4; ++i)
+ memset(&g_winxinput_states[i], 0, sizeof(winxinput_joypad_state));
+
+ FreeLibrary(g_winxinput_dll);
+ g_winxinput_dll = NULL;
+ g_XInputGetStateEx = NULL;
+
+ dinput_joypad.destroy();
+ g_xinput_block_pads = false;
+}
+
+// Buttons are provided by XInput as bits of a uint16.
+// Map from rarch button index (0..10) to a mask to bitwise-& the buttons against.
+// dpad is handled seperately.
+static const uint16_t button_index_to_bitmap_code[] = {
+ XINPUT_GAMEPAD_A,
+ XINPUT_GAMEPAD_B,
+ XINPUT_GAMEPAD_X,
+ XINPUT_GAMEPAD_Y,
+ XINPUT_GAMEPAD_LEFT_SHOULDER,
+ XINPUT_GAMEPAD_RIGHT_SHOULDER,
+ XINPUT_GAMEPAD_START,
+ XINPUT_GAMEPAD_BACK,
+ XINPUT_GAMEPAD_LEFT_THUMB,
+ XINPUT_GAMEPAD_RIGHT_THUMB,
+ XINPUT_GAMEPAD_GUIDE
+};
+
+static bool winxinput_joypad_button (unsigned port_num, uint16_t joykey)
+{
+ if (joykey == NO_BTN)
+ return false;
+
+ int xplayer = pad_index_to_xplayer_index(port_num);
+ if (xplayer == -1)
+ return dinput_joypad.button(port_num, joykey);
+
+ if (!(g_winxinput_states[xplayer].connected))
+ return false;
+
+ //return false;
+
+ uint16_t btn_word = g_winxinput_states[xplayer].xstate.Gamepad.wButtons;
+
+ if (GET_HAT_DIR(joykey))
+ {
+ switch (GET_HAT_DIR(joykey))
+ {
+ case HAT_UP_MASK: return btn_word & XINPUT_GAMEPAD_DPAD_UP;
+ case HAT_DOWN_MASK: return btn_word & XINPUT_GAMEPAD_DPAD_DOWN;
+ case HAT_LEFT_MASK: return btn_word & XINPUT_GAMEPAD_DPAD_LEFT;
+ case HAT_RIGHT_MASK: return btn_word & XINPUT_GAMEPAD_DPAD_RIGHT;
+ }
+ return false; // hat requested and no hat button down
+ }
+ else
+ {
+ // non-hat button
+ unsigned num_buttons = g_winxinput_guide_button_supported ? 11 : 10;
+
+ if (joykey < num_buttons)
+ return btn_word & button_index_to_bitmap_code[joykey];
+ }
+ return false;
+}
+
+static int16_t winxinput_joypad_axis (unsigned port_num, uint32_t joyaxis)
+{
+ if (joyaxis == AXIS_NONE)
+ return 0;
+
+ int xplayer = pad_index_to_xplayer_index(port_num);
+
+ if (xplayer == -1)
+ return dinput_joypad.axis(port_num, joyaxis);
+
+ if (!(g_winxinput_states[xplayer].connected))
+ return false;
+
+ int16_t val = 0;
+ int axis = -1;
+
+ bool is_neg = false;
+ bool is_pos = false;
+
+ if (AXIS_NEG_GET(joyaxis) <= 3) // triggers (axes 4,5) cannot be negative
+ {
+ axis = AXIS_NEG_GET(joyaxis);
+ is_neg = true;
+ }
+ else if (AXIS_POS_GET(joyaxis) <= 5)
+ {
+ axis = AXIS_POS_GET(joyaxis);
+ is_pos = true;
+ }
+
+ XINPUT_GAMEPAD* pad = &(g_winxinput_states[xplayer].xstate.Gamepad);
+
+ switch (axis)
+ {
+ case 0: val = pad->sThumbLX; break;
+ case 1: val = pad->sThumbLY; break;
+ case 2: val = pad->sThumbRX; break;
+ case 3: val = pad->sThumbRY; break;
+
+ case 4: val = pad->bLeftTrigger * 32767 / 255; break; // map 0..255 to 0..32767
+ case 5: val = pad->bRightTrigger * 32767 / 255; break;
+ }
+
+ if (is_neg && val > 0)
+ val = 0;
+ else if (is_pos && val < 0)
+ val = 0;
+
+ // Clamp to avoid overflow error
+ if (val == -32768)
+ val = -32767;
+
+ return val;
+}
+
+static void winxinput_joypad_poll(void)
+{
+ for (unsigned i = 0; i < 4; ++i)
+ if (g_winxinput_states[i].connected)
+ if (g_XInputGetStateEx(i, &(g_winxinput_states[i].xstate)) == ERROR_DEVICE_NOT_CONNECTED)
+ g_winxinput_states[i].connected = false;
+
+ dinput_joypad.poll();
+}
+
+const rarch_joypad_driver_t winxinput_joypad = {
+ winxinput_joypad_init,
+ winxinput_joypad_query_pad,
+ winxinput_joypad_destroy,
+ winxinput_joypad_button,
+ winxinput_joypad_axis,
+ winxinput_joypad_poll,
+ winxinput_joypad_name,
+ "winxinput",
+};
diff --git a/libretro-test/Makefile b/libretro-test/Makefile
index 15853aaeeb..1998f05f22 100644
--- a/libretro-test/Makefile
+++ b/libretro-test/Makefile
@@ -1,4 +1,8 @@
+ifneq ($(EMSCRIPTEN),)
+ platform = emscripten
+endif
+
ifeq ($(platform),)
platform = unix
ifeq ($(shell uname -a),)
@@ -32,6 +36,10 @@ else ifeq ($(platform), qnx)
TARGET := $(TARGET_NAME)_libretro_qnx.so
fpic := -fPIC
SHARED := -shared -Wl,--version-script=link.T -Wl,--no-undefined
+else ifeq ($(platform), emscripten)
+ TARGET := $(TARGET_NAME)_libretro_emscripten.so
+ fpic := -fPIC
+ SHARED := -shared -Wl,--version-script=link.T -Wl,--no-undefined
else
CC = gcc
TARGET := $(TARGET_NAME)_retro.dll
diff --git a/libretro.h b/libretro.h
index 0af84e6548..8d23356138 100755
--- a/libretro.h
+++ b/libretro.h
@@ -357,6 +357,8 @@ enum retro_mod
// If set, this call is not part of the public libretro API yet. It can change or be removed at any time.
#define RETRO_ENVIRONMENT_EXPERIMENTAL 0x10000
+// Environment callback to be used internally in frontend.
+#define RETRO_ENVIRONMENT_PRIVATE 0x20000
// Environment commands.
#define RETRO_ENVIRONMENT_SET_ROTATION 1 // const unsigned * --
@@ -445,7 +447,7 @@ enum retro_mod
// If HW rendering is used, pass only RETRO_HW_FRAME_BUFFER_VALID or NULL to retro_video_refresh_t.
#define RETRO_ENVIRONMENT_GET_VARIABLE 15
// struct retro_variable * --
- // Interface to aquire user-defined information from environment
+ // Interface to acquire user-defined information from environment
// that cannot feasibly be supported in a multi-system way.
// 'key' should be set to a key which has already been set by SET_VARIABLES.
// 'data' will be set to a value or NULL.
@@ -487,7 +489,10 @@ enum retro_mod
// NULL is returned if the libretro was loaded statically (i.e. linked statically to frontend), or if the path cannot be determined.
// Mostly useful in cooperation with SET_SUPPORT_NO_GAME as assets can be loaded without ugly hacks.
//
-#define RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK 20
+ //
+// Environment 20 was an obsolete version of SET_AUDIO_CALLBACK. It was not used by any known core at the time,
+// and was removed from the API.
+#define RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK 22
// const struct retro_audio_callback * --
// Sets an interface which is used to notify a libretro core about audio being available for writing.
// The callback can be called from any thread, so a core using this must have a thread safe audio implementation.
@@ -509,13 +514,19 @@ enum retro_mod
// Lets the core know how much time has passed since last invocation of retro_run().
// The frontend can tamper with the timing to fake fast-forward, slow-motion, frame stepping, etc.
// In this case the delta time will use the reference value in frame_time_callback..
-
+
// Notifies libretro that audio data should be written.
typedef void (*retro_audio_callback_t)(void);
+
+// True: Audio driver in frontend is active, and callback is expected to be called regularily.
+// False: Audio driver in frontend is paused or inactive. Audio callback will not be called until set_state has been called with true.
+// Initial state is false (inactive).
+typedef void (*retro_audio_set_state_callback_t)(bool enabled);
struct retro_audio_callback
{
retro_audio_callback_t callback;
+ retro_audio_set_state_callback_t set_state;
};
// Notifies a libretro core of time spent since last invocation of retro_run() in microseconds.
@@ -575,7 +586,7 @@ struct retro_hw_render_callback
// The reset callback might still be called in extreme situations such as if the context is lost beyond recovery.
// For optimal stability, set this to false, and allow context to be reset at any time.
retro_hw_context_reset_t context_destroy; // A callback to be called before the context is destroyed. Resources can be deinitialized at this step. This can be set to NULL, in which resources will just be destroyed without any notification.
- bool debug_context; // Creates a debug context. Only takes effect when using GL core.
+ bool debug_context; // Creates a debug context.
};
// Callback type passed in RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK. Called by the frontend in response to keyboard events.
diff --git a/libretro_private.h b/libretro_private.h
new file mode 100644
index 0000000000..a393412911
--- /dev/null
+++ b/libretro_private.h
@@ -0,0 +1,45 @@
+/* Copyright (C) 2010-2013 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this libretro API header (libretro_private.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef LIBRETRO_PRIVATE_H__
+#define LIBRETRO_PRIVATE_H__
+
+// Private additions to libretro. No API/ABI stability guaranteed.
+
+#include "libretro.h"
+
+#define RETRO_ENVIRONMENT_SET_LIBRETRO_PATH (RETRO_ENVIRONMENT_PRIVATE | 0)
+ // const char * --
+ // Sets the absolute path for the libretro core pointed to. RETRO_ENVIRONMENT_EXEC will use the last libretro core set with this call.
+ // Returns false if file for absolute path could not be found.
+#define RETRO_ENVIRONMENT_EXEC (RETRO_ENVIRONMENT_PRIVATE | 1)
+ // const char * --
+ // Requests that this core is deinitialized, and a new core is loaded.
+ // The libretro core used is set with SET_LIBRETRO_PATH, and path to game is passed in _EXEC. NULL means no game.
+#define RETRO_ENVIRONMENT_EXEC_ESCAPE (RETRO_ENVIRONMENT_PRIVATE | 2)
+ // const char * --
+ // Requests that this core is deinitialized, and a new core is loaded. It also escapes the main loop the core is currently
+ // bound to.
+ // The libretro core used is set with SET_LIBRETRO_PATH, and path to game is passed in _EXEC. NULL means no game.
+
+#endif
+
diff --git a/media/overlays/gameboy-landscape.cfg b/media/overlays/gameboy-landscape.cfg
index e2964c61f6..bc7e838c11 100644
--- a/media/overlays/gameboy-landscape.cfg
+++ b/media/overlays/gameboy-landscape.cfg
@@ -8,19 +8,19 @@ overlay0_full_screen = true
overlay1_full_screen = true
overlay0_descs = 14
-overlay0_desc0 = "left,32,393,rect,25,25"
-overlay0_desc1 = "right,113,393,rect,25,25"
-overlay0_desc2 = "up,73,349,rect,25,25"
-overlay0_desc3 = "down,73,436,rect,25,25"
+overlay0_desc0 = "left,12,389,rect,50,40"
+overlay0_desc1 = "right,134,389,rect,50,40"
+overlay0_desc2 = "up,76,334,rect,40,50"
+overlay0_desc3 = "down,76,444,rect,40,50"
overlay0_desc4 = "select,730,115,rect,30,30"
overlay0_desc5 = "start,730,48,rect,30,30"
-overlay0_desc6 = "b,697,418,radial,30,30"
-overlay0_desc7 = "a,762,370,radial,30,30"
+overlay0_desc6 = "b,690,418,radial,46,46"
+overlay0_desc7 = "a,772,370,radial,46,46"
overlay0_desc8 = "overlay_next,731,239,radial,30,30"
-overlay0_desc9 = "left|up,28,348,radial,20,20"
-overlay0_desc10 = "left|down,28,435,radial,20,20"
-overlay0_desc11 = "right|up,117,348,radial,20,20"
-overlay0_desc12 = "right|down,117,435,radial,20,20"
+overlay0_desc9 = "left|up,10,324,radial,22,22"
+overlay0_desc10 = "left|down,10,454,radial,22,22"
+overlay0_desc11 = "right|up,140,324,radial,22,22"
+overlay0_desc12 = "right|down,140,454,radial,22,22"
overlay0_desc13 = "menu_toggle,73,49,radial,20,20"
overlay1_descs = 11
@@ -38,4 +38,4 @@ overlay1_desc10 = "overlay_next,400,452,radial,22,22"
overlay2_descs = 1
overlay2_rect = "0.47,0.9,0.07,0.08"
-overlay2_desc0 = "overlay_next,16,16,radial,16,16"
\ No newline at end of file
+overlay2_desc0 = "overlay_next,16,16,radial,16,16"
diff --git a/media/overlays/gameboy-portrait.cfg b/media/overlays/gameboy-portrait.cfg
index caa4266788..6239aa4105 100644
--- a/media/overlays/gameboy-portrait.cfg
+++ b/media/overlays/gameboy-portrait.cfg
@@ -9,19 +9,19 @@ overlay1_full_screen = true
overlay2_full_screen = true
overlay0_descs = 14
-overlay0_desc0 = "left,44,702,rect,25,25"
-overlay0_desc1 = "right,162,702,rect,25,25"
-overlay0_desc2 = "up,102,643,rect,25,25"
-overlay0_desc3 = "down,102,761,rect,25,25"
+overlay0_desc0 = "left,42,700,rect,56,46"
+overlay0_desc1 = "right,148,700,rect,56,46"
+overlay0_desc2 = "up,96,646,rect,46,56"
+overlay0_desc3 = "down,96,758,rect,46,56"
overlay0_desc4 = "select,55,491,rect,40,40"
overlay0_desc5 = "start,423,491,rect,40,40"
-overlay0_desc6 = "b,317,726,radial,45,45"
-overlay0_desc7 = "a,420,655,radial,45,45"
+overlay0_desc6 = "b,317,726,radial,65,65"
+overlay0_desc7 = "a,420,655,radial,65,65"
overlay0_desc8 = "overlay_next,240,490,radial,30,30"
-overlay0_desc9 = "left|up,44,643,radial,20,20"
-overlay0_desc10 = "left|down,44,761,radial,20,20"
-overlay0_desc11 = "right|up,162,643,radial,20,20"
-overlay0_desc12 = "right|down,162,761,radial,20,20"
+overlay0_desc9 = "left|up,24,634,radial,45,45"
+overlay0_desc10 = "left|down,24,772,radial,45,45"
+overlay0_desc11 = "right|up,160,634,radial,45,45"
+overlay0_desc12 = "right|down,160,772,radial,45,45"
overlay0_desc13 = "menu_toggle,240,595,rect,40,28"
overlay1_descs = 11
@@ -39,4 +39,4 @@ overlay1_desc10 = "overlay_next,240,683,radial,25,25"
overlay2_descs = 1
overlay2_rect = "0.47,0.9,0.11,0.08"
-overlay2_desc0 = "overlay_next,16,16,radial,16,16"
\ No newline at end of file
+overlay2_desc0 = "overlay_next,16,16,radial,16,16"
diff --git a/media/overlays/genesis3-landscape.cfg b/media/overlays/genesis3-landscape.cfg
index 2c7322b46e..af01859583 100644
--- a/media/overlays/genesis3-landscape.cfg
+++ b/media/overlays/genesis3-landscape.cfg
@@ -8,19 +8,19 @@ overlay0_full_screen = true
overlay1_full_screen = true
overlay0_descs = 14
-overlay0_desc0 = "left,34,393,rect,25,25"
-overlay0_desc1 = "right,110,393,rect,25,25"
-overlay0_desc2 = "up,70,360,rect,25,25"
-overlay0_desc3 = "down,70,432,rect,25,25"
+overlay0_desc0 = "left,12,389,rect,50,40"
+overlay0_desc1 = "right,134,389,rect,50,40"
+overlay0_desc2 = "up,76,334,rect,40,50"
+overlay0_desc3 = "down,76,444,rect,40,50"
overlay0_desc4 = "start,730,48,rect,30,30"
-overlay0_desc5 = "a,764,388,rect,26,26"
-overlay0_desc6 = "b,697,412,radial,26,26"
-overlay0_desc7 = "y,634,439,radial,26,26"
+overlay0_desc5 = "a,764,388,rect,30,30"
+overlay0_desc6 = "b,697,412,radial,30,30"
+overlay0_desc7 = "y,634,439,radial,30,30"
overlay0_desc8 = "overlay_next,728,186,radial,30,30"
-overlay0_desc9 = "left|up,32,354,radial,20,20"
-overlay0_desc10 = "left|down,32,432,radial,20,20"
-overlay0_desc11 = "right|up,111,354,radial,20,20"
-overlay0_desc12 = "right|down,111,432,radial,20,20"
+overlay0_desc9 = "left|up,10,324,radial,22,22"
+overlay0_desc10 = "left|down,10,454,radial,22,22"
+overlay0_desc11 = "right|up,140,324,radial,22,22"
+overlay0_desc12 = "right|down,140,454,radial,22,22"
overlay0_desc13 = "menu_toggle,73,50,radial,20,20"
overlay1_descs = 11
@@ -38,4 +38,4 @@ overlay1_desc10 = "overlay_next,400,452,radial,22,22"
overlay2_descs = 1
overlay2_rect = "0.47,0.9,0.07,0.08"
-overlay2_desc0 = "overlay_next,16,16,radial,16,16"
\ No newline at end of file
+overlay2_desc0 = "overlay_next,16,16,radial,16,16"
diff --git a/media/overlays/genesis3-portrait.cfg b/media/overlays/genesis3-portrait.cfg
index 86276708a4..36c148248e 100644
--- a/media/overlays/genesis3-portrait.cfg
+++ b/media/overlays/genesis3-portrait.cfg
@@ -9,19 +9,19 @@ overlay1_full_screen = true
overlay2_full_screen = true
overlay0_descs = 14
-overlay0_desc0 = "left,52,695,rect,25,25"
-overlay0_desc1 = "right,159,695,rect,25,25"
-overlay0_desc2 = "up,107,638,rect,25,25"
-overlay0_desc3 = "down,107,744,rect,25,25"
+overlay0_desc0 = "left,42,700,rect,56,46"
+overlay0_desc1 = "right,148,700,rect,56,46"
+overlay0_desc2 = "up,96,646,rect,46,56"
+overlay0_desc3 = "down,96,758,rect,46,56"
overlay0_desc4 = "start,427,507,rect,40,40"
-overlay0_desc5 = "a,449,720,radial,25,25"
-overlay0_desc6 = "b,374,736,radial,25,25"
-overlay0_desc7 = "y,301,755,rect,25,25"
+overlay0_desc5 = "a,445,715,radial,35,55"
+overlay0_desc6 = "b,374,736,radial,35,55"
+overlay0_desc7 = "y,301,755,rect,35,55"
overlay0_desc8 = "overlay_next,107,508,radial,40,40"
-overlay0_desc9 = "left|up,52,638,radial,25,25"
-overlay0_desc10 = "left|down,52,744,radial,25,25"
-overlay0_desc11 = "right|up,159,638,radial,25,25"
-overlay0_desc12 = "right|down,159,744,radial,25,25"
+overlay0_desc9 = "left|up,24,634,radial,45,45"
+overlay0_desc10 = "left|down,24,772,radial,45,45"
+overlay0_desc11 = "right|up,160,634,radial,45,45"
+overlay0_desc12 = "right|down,160,772,radial,45,45"
overlay0_desc13 = "menu_toggle,240,575,rect,40,28"
overlay1_descs = 11
@@ -39,4 +39,4 @@ overlay1_desc10 = "overlay_next,240,683,radial,30,30"
overlay2_descs = 1
overlay2_rect = "0.47,0.9,0.11,0.08"
-overlay2_desc0 = "overlay_next,16,16,radial,16,16"
\ No newline at end of file
+overlay2_desc0 = "overlay_next,16,16,radial,16,16"
diff --git a/media/overlays/genesis6-landscape.cfg b/media/overlays/genesis6-landscape.cfg
index 37c09a69d4..23318ea7c5 100644
--- a/media/overlays/genesis6-landscape.cfg
+++ b/media/overlays/genesis6-landscape.cfg
@@ -8,10 +8,10 @@ overlay0_full_screen = true
overlay1_full_screen = true
overlay0_descs = 17
-overlay0_desc0 = "left,34,393,rect,25,25"
-overlay0_desc1 = "right,110,393,rect,25,25"
-overlay0_desc2 = "up,70,360,rect,25,25"
-overlay0_desc3 = "down,70,432,rect,25,25"
+overlay0_desc0 = "left,12,389,rect,50,40"
+overlay0_desc1 = "right,134,389,rect,50,40"
+overlay0_desc2 = "up,76,334,rect,40,50"
+overlay0_desc3 = "down,76,444,rect,40,50"
overlay0_desc4 = "start,730,48,rect,30,30"
overlay0_desc5 = "a,764,388,rect,26,26"
overlay0_desc6 = "b,697,412,radial,26,26"
@@ -20,10 +20,10 @@ overlay0_desc8 = "l,608,374,rect,24,24"
overlay0_desc9 = "x,670,350,radial,24,24"
overlay0_desc10 = "r,736,326,radial,24,17"
overlay0_desc11 = "overlay_next,728,186,radial,30,30"
-overlay0_desc12 = "left|up,32,354,radial,20,20"
-overlay0_desc13 = "left|down,32,432,radial,20,20"
-overlay0_desc14 = "right|up,111,354,radial,20,20"
-overlay0_desc15 = "right|down,111,432,radial,20,20"
+overlay0_desc12 = "left|up,10,324,radial,22,22"
+overlay0_desc13 = "left|down,10,454,radial,22,22"
+overlay0_desc14 = "right|up,140,324,radial,22,22"
+overlay0_desc15 = "right|down,140,454,radial,22,22"
overlay0_desc16 = "menu_toggle,73,50,radial,20,20"
overlay1_descs = 11
@@ -41,4 +41,4 @@ overlay1_desc10 = "overlay_next,400,452,radial,22,22"
overlay2_descs = 1
overlay2_rect = "0.47,0.9,0.07,0.08"
-overlay2_desc0 = "overlay_next,16,16,radial,16,16"
\ No newline at end of file
+overlay2_desc0 = "overlay_next,16,16,radial,16,16"
diff --git a/media/overlays/genesis6-portrait.cfg b/media/overlays/genesis6-portrait.cfg
index 8636715429..bdea9ec72d 100644
--- a/media/overlays/genesis6-portrait.cfg
+++ b/media/overlays/genesis6-portrait.cfg
@@ -9,10 +9,10 @@ overlay1_full_screen = true
overlay2_full_screen = true
overlay0_descs = 17
-overlay0_desc0 = "left,52,695,rect,25,25"
-overlay0_desc1 = "right,159,695,rect,25,25"
-overlay0_desc2 = "up,107,638,rect,25,25"
-overlay0_desc3 = "down,107,744,rect,25,25"
+overlay0_desc0 = "left,42,700,rect,56,46"
+overlay0_desc1 = "right,148,700,rect,56,46"
+overlay0_desc2 = "up,96,646,rect,46,56"
+overlay0_desc3 = "down,96,758,rect,46,56"
overlay0_desc4 = "start,427,507,rect,40,40"
overlay0_desc5 = "a,449,720,radial,25,25"
overlay0_desc6 = "b,374,736,radial,25,25"
@@ -21,10 +21,10 @@ overlay0_desc8 = "l,283,684,rect,21,21"
overlay0_desc9 = "x,352,666,radial,21,21"
overlay0_desc10 = "r,426,648,radial,21,21"
overlay0_desc11 = "overlay_next,107,508,radial,40,40"
-overlay0_desc12 = "left|up,52,638,radial,25,25"
-overlay0_desc13 = "left|down,52,744,radial,25,25"
-overlay0_desc14 = "right|up,159,638,radial,25,25"
-overlay0_desc15 = "right|down,159,744,radial,25,25"
+overlay0_desc12 = "left|up,24,634,radial,45,45"
+overlay0_desc13 = "left|down,24,772,radial,45,45"
+overlay0_desc14 = "right|up,160,634,radial,45,45"
+overlay0_desc15 = "right|down,160,772,radial,45,45"
overlay0_desc16 = "menu_toggle,240,575,rect,40,28"
overlay1_descs = 11
@@ -42,4 +42,4 @@ overlay1_desc10 = "overlay_next,240,683,radial,30,30"
overlay2_descs = 1
overlay2_rect = "0.47,0.9,0.11,0.08"
-overlay2_desc0 = "overlay_next,16,16,radial,16,16"
\ No newline at end of file
+overlay2_desc0 = "overlay_next,16,16,radial,16,16"
diff --git a/media/overlays/nes-landscape.cfg b/media/overlays/nes-landscape.cfg
index 8f3d94ef33..a7111e5729 100644
--- a/media/overlays/nes-landscape.cfg
+++ b/media/overlays/nes-landscape.cfg
@@ -8,19 +8,19 @@ overlay0_full_screen = true
overlay1_full_screen = true
overlay0_descs = 14
-overlay0_desc0 = "left,33,399,rect,20,20"
-overlay0_desc1 = "right,122,399,rect,20,20"
-overlay0_desc2 = "up,77,355,rect,20,20"
-overlay0_desc3 = "down,77,443,rect,20,20"
+overlay0_desc0 = "left,12,388,rect,50,36"
+overlay0_desc1 = "right,134,388,rect,50,36"
+overlay0_desc2 = "up,76,334,rect,40,50"
+overlay0_desc3 = "down,76,444,rect,40,50"
overlay0_desc4 = "select,54,35,rect,45,20"
overlay0_desc5 = "start,745,35,rect,45,20"
-overlay0_desc6 = "b,685,424,radial,30,30"
-overlay0_desc7 = "a,759,424,radial,30,30"
+overlay0_desc6 = "b,685,424,radial,46,46"
+overlay0_desc7 = "a,759,424,radial,46,46"
overlay0_desc8 = "overlay_next,743,204,radial,30,30"
-overlay0_desc9 = "left|up,29,350,radial,20,20"
-overlay0_desc10 = "left|down,29,440,radial,20,20"
-overlay0_desc11 = "right|up,121,350,radial,20,20"
-overlay0_desc12 = "right|down,121,440,radial,20,20"
+overlay0_desc9 = "left|up,10,328,radial,26,26"
+overlay0_desc10 = "left|down,10,454,radial,26,26"
+overlay0_desc11 = "right|up,140,328,radial,26,26"
+overlay0_desc12 = "right|down,140,454,radial,26,26"
overlay0_desc13 = "menu_toggle,76,205,radial,20,20"
overlay1_descs = 11
@@ -38,4 +38,4 @@ overlay1_desc10 = "overlay_next,400,452,radial,22,22"
overlay2_descs = 1
overlay2_rect = "0.47,0.9,0.07,0.08"
-overlay2_desc0 = "overlay_next,16,16,radial,16,16"
\ No newline at end of file
+overlay2_desc0 = "overlay_next,16,16,radial,16,16"
diff --git a/media/overlays/nes-portrait.cfg b/media/overlays/nes-portrait.cfg
index cdab629f09..ff940f1194 100644
--- a/media/overlays/nes-portrait.cfg
+++ b/media/overlays/nes-portrait.cfg
@@ -9,19 +9,19 @@ overlay1_full_screen = true
overlay2_full_screen = true
overlay0_descs = 14
-overlay0_desc0 = "left,39,701,rect,30,30"
-overlay0_desc1 = "right,156,701,rect,30,30"
-overlay0_desc2 = "up,97,641,rect,30,30"
-overlay0_desc3 = "down,97,758,rect,30,30"
-overlay0_desc4 = "select,55,485,rect,45,20"
-overlay0_desc5 = "start,425,485,rect,45,20"
-overlay0_desc6 = "b,309,702,radial,48,48"
-overlay0_desc7 = "a,424,702,radial,48,48"
+overlay0_desc0 = "left,42,700,rect,56,46"
+overlay0_desc1 = "right,148,700,rect,56,46"
+overlay0_desc2 = "up,96,646,rect,46,56"
+overlay0_desc3 = "down,96,758,rect,46,56"
+overlay0_desc4 = "select,55,485,rect,45,20"
+overlay0_desc5 = "start,425,485,rect,45,20"
+overlay0_desc6 = "b,309,698,radial,48,54"
+overlay0_desc7 = "a,424,698,radial,48,54"
overlay0_desc8 = "overlay_next,241,492,radial,30,30"
-overlay0_desc9 = "left|up,39,641,radial,30,30"
-overlay0_desc10 = "left|down,39,758,radial,30,30"
-overlay0_desc11 = "right|up,156,641,radial,30,30"
-overlay0_desc12 = "right|down,156,758,radial,30,30"
+overlay0_desc9 = "left|up,28,638,radial,45,45"
+overlay0_desc10 = "left|down,28,768,radial,45,45"
+overlay0_desc11 = "right|up,160,638,radial,45,45"
+overlay0_desc12 = "right|down,160,768,radial,45,45"
overlay0_desc13 = "menu_toggle,240,595,rect,40,28"
overlay1_descs = 11
@@ -39,4 +39,4 @@ overlay1_desc10 = "overlay_next,240,683,radial,25,25"
overlay2_descs = 1
overlay2_rect = "0.47,0.9,0.11,0.08"
-overlay2_desc0 = "overlay_next,16,16,radial,16,16"
\ No newline at end of file
+overlay2_desc0 = "overlay_next,16,16,radial,16,16"
diff --git a/media/overlays/psx-landscape.cfg b/media/overlays/psx-landscape.cfg
index 18ea569070..efd92f8471 100644
--- a/media/overlays/psx-landscape.cfg
+++ b/media/overlays/psx-landscape.cfg
@@ -8,25 +8,25 @@ overlay0_full_screen = true
overlay1_full_screen = true
overlay0_descs = 20
-overlay0_desc0 = "left,34,395,rect,25,25"
-overlay0_desc1 = "right,112,395,rect,25,25"
-overlay0_desc2 = "up,70,356,rect,25,25"
-overlay0_desc3 = "down,70,432,rect,25,25"
+overlay0_desc0 = "left,8,384,rect,50,40"
+overlay0_desc1 = "right,134,384,rect,50,40"
+overlay0_desc2 = "up,72,334,rect,40,50"
+overlay0_desc3 = "down,72,444,rect,40,50"
overlay0_desc4 = "start,434,33,rect,30,17"
overlay0_desc5 = "select,369,33,rect,30,17"
-overlay0_desc6 = "a,776,390,radial,25,25"
-overlay0_desc7 = "b,726,438,radial,25,25"
-overlay0_desc8 = "x,726,338,radial,25,25"
-overlay0_desc9 = "y,677,390,radial,25,25"
+overlay0_desc6 = "a,776,390,radial,30,30"
+overlay0_desc7 = "b,726,438,radial,30,30"
+overlay0_desc8 = "x,726,338,radial,30,30"
+overlay0_desc9 = "y,677,390,radial,30,30"
overlay0_desc10 = "l,71,110,rect,47,27"
overlay0_desc11 = "l2,70,37,rect,47,27"
overlay0_desc12 = "r,730,110,rect,47,27"
overlay0_desc13 = "r2,730,37,rect,47,27"
overlay0_desc14 = "overlay_next,401,437,radial,20,20"
-overlay0_desc15 = "left|up,34,356,radial,20,20"
-overlay0_desc16 = "left|down,34,432,radial,20,20"
-overlay0_desc17 = "right|up,112,356,radial,20,20"
-overlay0_desc18 = "right|down,112,432,radial,20,20"
+overlay0_desc15 = "left|up,10,324,radial,28,28"
+overlay0_desc16 = "left|down,10,454,radial,28,28"
+overlay0_desc17 = "right|up,140,324,radial,28,28"
+overlay0_desc18 = "right|down,140,454,radial,28,28"
overlay0_desc19 = "menu_toggle,732,217,rect,25,20"
overlay1_descs = 11
@@ -44,4 +44,4 @@ overlay1_desc10 = "overlay_next,403,453,radial,25,25"
overlay2_descs = 1
overlay2_rect = "0.47,0.9,0.07,0.08"
-overlay2_desc0 = "overlay_next,16,16,radial,16,16"
\ No newline at end of file
+overlay2_desc0 = "overlay_next,16,16,radial,16,16"
diff --git a/media/overlays/psx-portrait.cfg b/media/overlays/psx-portrait.cfg
index a62183d0fa..2a5716a882 100644
--- a/media/overlays/psx-portrait.cfg
+++ b/media/overlays/psx-portrait.cfg
@@ -9,10 +9,10 @@ overlay1_full_screen = true
overlay2_full_screen = true
overlay0_descs = 20
-overlay0_desc0 = "left,41,695,rect,25,25"
-overlay0_desc1 = "right,157,695,rect,25,25"
-overlay0_desc2 = "up,98,637,rect,25,25"
-overlay0_desc3 = "down,98,751,rect,25,25"
+overlay0_desc0 = "left,42,700,rect,56,46"
+overlay0_desc1 = "right,148,700,rect,56,46"
+overlay0_desc2 = "up,96,646,rect,46,56"
+overlay0_desc3 = "down,96,758,rect,46,56"
overlay0_desc4 = "start,286,497,rect,35,17"
overlay0_desc5 = "select,197,497,rect,35,17"
overlay0_desc6 = "a,436,699,radial,35,35"
@@ -24,10 +24,10 @@ overlay0_desc11 = "l2,50,479,rect,50,27"
overlay0_desc12 = "r,430,537,rect,50,27"
overlay0_desc13 = "r2,430,479,rect,50,27"
overlay0_desc14 = "overlay_next,240,578,radial,30,30"
-overlay0_desc15 = "left|up,41,637,radial,20,20"
-overlay0_desc16 = "left|down,41,751,radial,20,20"
-overlay0_desc17 = "right|up,157,637,radial,20,20"
-overlay0_desc18 = "right|down,157,751,radial,20,20"
+overlay0_desc15 = "left|up,20,638,radial,45,45"
+overlay0_desc16 = "left|down,20,768,radial,45,45"
+overlay0_desc17 = "right|up,160,638,radial,45,45"
+overlay0_desc18 = "right|down,166,768,radial,45,45"
overlay0_desc19 = "menu_toggle,240,764,rect,25,20"
overlay1_descs = 11
@@ -45,4 +45,4 @@ overlay1_desc10 = "overlay_next,240,683,radial,25,25"
overlay2_descs = 1
overlay2_rect = "0.47,0.9,0.11,0.08"
-overlay2_desc0 = "overlay_next,16,16,radial,16,16"
\ No newline at end of file
+overlay2_desc0 = "overlay_next,16,16,radial,16,16"
diff --git a/media/overlays/snes-landscape.cfg b/media/overlays/snes-landscape.cfg
index cac51d5d6f..700c8741ce 100644
--- a/media/overlays/snes-landscape.cfg
+++ b/media/overlays/snes-landscape.cfg
@@ -8,23 +8,23 @@ overlay0_full_screen = true
overlay1_full_screen = true
overlay0_descs = 18
-overlay0_desc0 = "left,28,389,rect,30,30"
-overlay0_desc1 = "right,117,389,rect,30,30"
-overlay0_desc2 = "up,73,344,rect,30,30"
-overlay0_desc3 = "down,73,434,rect,30,30"
-overlay0_desc4 = "select,71,218,rect,30,30"
-overlay0_desc5 = "start,71,148,rect,30,30"
-overlay0_desc6 = "b,707,432,radial,30,30"
-overlay0_desc7 = "a,764,386,radial,30,30"
-overlay0_desc8 = "x,707,338,radial,30,30"
-overlay0_desc9 = "y,653,386,radial,30,30"
-overlay0_desc10 = "l,70,31,rect,70,30"
-overlay0_desc11 = "r,731,31,rect,70,30"
+overlay0_desc0 = "left,12,389,rect,56,46"
+overlay0_desc1 = "right,134,389,rect,56,46"
+overlay0_desc2 = "up,71,334,rect,46,56"
+overlay0_desc3 = "down,71,444,rect,46,56"
+overlay0_desc4 = "select,71,218,rect,30,30"
+overlay0_desc5 = "start,71,148,rect,30,30"
+overlay0_desc6 = "b,707,444,radial,50,50"
+overlay0_desc7 = "a,774,386,radial,50,50"
+overlay0_desc8 = "x,707,320,radial,50,50"
+overlay0_desc9 = "y,636,386,radial,50,50"
+overlay0_desc10 = "l,70,31,rect,70,30"
+overlay0_desc11 = "r,731,31,rect,70,30"
overlay0_desc12 = "overlay_next,730,171,radial,30,30"
-overlay0_desc13 = "left|up,28,344,radial,20,20"
-overlay0_desc14 = "left|down,28,434,radial,20,20"
-overlay0_desc15 = "right|up,117,344,radial,20,20"
-overlay0_desc16 = "right|down,117,434,radial,20,20"
+overlay0_desc13 = "left|up,18,324,radial,28,28"
+overlay0_desc14 = "left|down,18,454,radial,28,28"
+overlay0_desc15 = "right|up,140,324,radial,28,28"
+overlay0_desc16 = "right|down,140,454,radial,28,28"
overlay0_desc17 = "menu_toggle,401,443,radial,20,20"
overlay1_descs = 11
@@ -42,4 +42,4 @@ overlay1_desc10 = "overlay_next,400,452,radial,22,22"
overlay2_descs = 1
overlay2_rect = "0.47,0.9,0.07,0.08"
-overlay2_desc0 = "overlay_next,16,16,radial,16,16"
\ No newline at end of file
+overlay2_desc0 = "overlay_next,16,16,radial,16,16"
diff --git a/media/overlays/snes-portrait.cfg b/media/overlays/snes-portrait.cfg
index 4eab5c8159..4426b49e91 100644
--- a/media/overlays/snes-portrait.cfg
+++ b/media/overlays/snes-portrait.cfg
@@ -9,23 +9,23 @@ overlay1_full_screen = true
overlay2_full_screen = true
overlay0_descs = 18
-overlay0_desc0 = "left,40,703,rect,30,30"
-overlay0_desc1 = "right,156,703,rect,30,30"
-overlay0_desc2 = "up,98,644,rect,30,30"
-overlay0_desc3 = "down,98,761,rect,30,30"
-overlay0_desc4 = "select,206,494,rect,30,30"
-overlay0_desc5 = "start,285,494,rect,30,30"
-overlay0_desc6 = "b,372,751,radial,35,35"
-overlay0_desc7 = "a,439,692,radial,35,35"
-overlay0_desc8 = "x,372,626,radial,35,35"
-overlay0_desc9 = "y,308,692,radial,35,35"
-overlay0_desc10 = "l,70,482,rect,70,30"
-overlay0_desc11 = "r,410,482,rect,70,30"
+overlay0_desc0 = "left,42,700,rect,56,46"
+overlay0_desc1 = "right,148,700,rect,56,46"
+overlay0_desc2 = "up,96,646,rect,46,56"
+overlay0_desc3 = "down,96,758,rect,46,56"
+overlay0_desc4 = "select,206,494,rect,30,30"
+overlay0_desc5 = "start,285,494,rect,30,30"
+overlay0_desc6 = "b,372,756,radial,90,90"
+overlay0_desc7 = "a,446,686,radial,90,90"
+overlay0_desc8 = "x,370,622,radial,90,90"
+overlay0_desc9 = "y,296,692,radial,90,90"
+overlay0_desc10 = "l,70,482,rect,70,30"
+overlay0_desc11 = "r,410,482,rect,70,30"
overlay0_desc12 = "overlay_next,241,587,radial,30,30"
-overlay0_desc13 = "left|up,40,644,radial,30,30"
-overlay0_desc14 = "left|down,40,761,radial,30,30"
-overlay0_desc15 = "right|up,156,644,radial,30,30"
-overlay0_desc16 = "right|down,156,761,radial,30,30"
+overlay0_desc13 = "left|up,28,638,radial,45,45"
+overlay0_desc14 = "left|down,28,768,radial,45,45"
+overlay0_desc15 = "right|up,160,638,radial,45,45"
+overlay0_desc16 = "right|down,160,768,radial,45,45"
overlay0_desc17 = "menu_toggle,240,760,radial,20,20"
overlay1_descs = 11
@@ -43,4 +43,4 @@ overlay1_desc10 = "overlay_next,240,683,radial,25,25"
overlay2_descs = 1
overlay2_rect = "0.47,0.9,0.11,0.08"
-overlay2_desc0 = "overlay_next,16,16,radial,16,16"
\ No newline at end of file
+overlay2_desc0 = "overlay_next,16,16,radial,16,16"
diff --git a/msvc/msvc-2010/RetroArch-msvc2010.sln b/msvc/msvc-2010/RetroArch-msvc2010.sln
new file mode 100644
index 0000000000..6bb4b9c199
--- /dev/null
+++ b/msvc/msvc-2010/RetroArch-msvc2010.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual C++ Express 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RetroArch-msvc2010", "RetroArch-msvc2010.vcxproj", "{27FF7CE1-4059-4AA1-8062-FD529560FA54}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {27FF7CE1-4059-4AA1-8062-FD529560FA54}.Debug|Win32.ActiveCfg = Debug|Win32
+ {27FF7CE1-4059-4AA1-8062-FD529560FA54}.Debug|Win32.Build.0 = Debug|Win32
+ {27FF7CE1-4059-4AA1-8062-FD529560FA54}.Release|Win32.ActiveCfg = Release|Win32
+ {27FF7CE1-4059-4AA1-8062-FD529560FA54}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/msvc/msvc-2010/RetroArch-msvc2010.vcxproj b/msvc/msvc-2010/RetroArch-msvc2010.vcxproj
index 17c46dec6d..4b037e80ea 100644
--- a/msvc/msvc-2010/RetroArch-msvc2010.vcxproj
+++ b/msvc/msvc-2010/RetroArch-msvc2010.vcxproj
@@ -88,7 +88,7 @@
Level3
Disabled
- WIN32;HAVE_WIN32_D3D9;HAVE_CG;HAVE_GLSL;HAVE_FBO;HAVE_ZLIB;WANT_MINIZ;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_SCREENSHOTS;HAVE_BSV_MOVIE;HAVE_DINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETPLAY;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_SECURE_NO_WARNINGS;__SSE__;__i686__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC
+ WIN32;HAVE_WIN32_D3D9;HAVE_CG;HAVE_GLSL;HAVE_FBO;HAVE_ZLIB;WANT_MINIZ;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_SCREENSHOTS;HAVE_BSV_MOVIE;HAVE_BUILTIN_AUTOCONFIG;HAVE_DINPUT;HAVE_WINXINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETPLAY;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_SECURE_NO_WARNINGS;__SSE__;__i686__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC
$(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\..\..\;$(CG_INC_PATH);%(AdditionalIncludeDirectories)
MultiThreadedDebug
CompileAsCpp
@@ -108,7 +108,7 @@
Level3
Disabled
- WIN32;HAVE_WIN32_D3D9;HAVE_CG;HAVE_GLSL;HAVE_FBO;HAVE_ZLIB;WANT_MINIZ;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_SCREENSHOTS;HAVE_BSV_MOVIE;HAVE_DINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETPLAY;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_SECURE_NO_WARNINGS;__SSE__;__SSE2__;__x86_64__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC
+ WIN32;HAVE_WIN32_D3D9;HAVE_CG;HAVE_GLSL;HAVE_FBO;HAVE_ZLIB;WANT_MINIZ;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_SCREENSHOTS;HAVE_BSV_MOVIE;HAVE_BUILTIN_AUTOCONFIG;HAVE_DINPUT;HAVE_WINXINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETPLAY;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_SECURE_NO_WARNINGS;__SSE__;__SSE2__;__x86_64__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC
$(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\..\..\;$(CG_INC_PATH);%(AdditionalIncludeDirectories)
MultiThreadedDebug
CompileAsCpp
@@ -130,7 +130,7 @@
MaxSpeed
true
true
- WIN32;HAVE_WIN32_D3D9;HAVE_CG;HAVE_GLSL;HAVE_FBO;HAVE_ZLIB;WANT_MINIZ;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_SCREENSHOTS;HAVE_BSV_MOVIE;HAVE_DINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETPLAY;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_SECURE_NO_WARNINGS;__SSE__;__i686__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC
+ WIN32;HAVE_WIN32_D3D9;HAVE_CG;HAVE_GLSL;HAVE_FBO;HAVE_ZLIB;WANT_MINIZ;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_SCREENSHOTS;HAVE_BSV_MOVIE;HAVE_BUILTIN_AUTOCONFIG;HAVE_DINPUT;HAVE_WINXINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETPLAY;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;_CRT_SECURE_NO_WARNINGS;__SSE__;__i686__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC
$(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\..\..\;$(CG_INC_PATH);%(AdditionalIncludeDirectories)
MultiThreaded
CompileAsCpp
@@ -154,7 +154,7 @@
MaxSpeed
true
true
- WIN32;HAVE_WIN32_D3D9;HAVE_CG;HAVE_GLSL;HAVE_FBO;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_SCREENSHOTS;HAVE_BSV_MOVIE;HAVE_DINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETPLAY;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;HAVE_ZLIB;WANT_MINIZ;_CRT_SECURE_NO_WARNINGS;__SSE__;__SSE2__;__x86_64__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC
+ WIN32;HAVE_WIN32_D3D9;HAVE_CG;HAVE_GLSL;HAVE_FBO;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_SCREENSHOTS;HAVE_BSV_MOVIE;HAVE_BUILTIN_AUTOCONFIG;HAVE_DINPUT;HAVE_WINXINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETPLAY;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;HAVE_ZLIB;WANT_MINIZ;_CRT_SECURE_NO_WARNINGS;__SSE__;__SSE2__;__x86_64__;HAVE_OVERLAY;HAVE_RGUI;HAVE_GL_SYNC
$(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\..\..\;$(CG_INC_PATH);%(AdditionalIncludeDirectories)
MultiThreaded
CompileAsCpp
@@ -250,8 +250,12 @@
+
+
+
+
diff --git a/performance.c b/performance.c
index 7829fe265d..faad97135d 100644
--- a/performance.c
+++ b/performance.c
@@ -58,6 +58,10 @@
#include
#endif
+#ifdef EMSCRIPTEN
+#include
+#endif
+
#ifdef PERF_TEST
#define MAX_COUNTERS 64
static struct rarch_perf_counter *perf_counters[MAX_COUNTERS];
@@ -145,6 +149,8 @@ rarch_time_t rarch_get_time_usec(void)
if (clock_gettime(CLOCK_MONOTONIC, &tv) < 0)
return 0;
return tv.tv_sec * INT64_C(1000000) + (tv.tv_nsec + 500) / 1000;
+#elif defined(EMSCRIPTEN)
+ return emscripten_get_now() * 1000;
#else
#error "Your platform does not have a timer function implemented in rarch_get_time_usec(). Cannot continue."
#endif
diff --git a/retroarch-mingw-build.sh b/retroarch-mingw-build.sh
index 3f9640a4f4..1f6135a03c 100755
--- a/retroarch-mingw-build.sh
+++ b/retroarch-mingw-build.sh
@@ -83,7 +83,7 @@ do_build()
BUILDTYPE="$3"
if [ ! -d "$RetroArch_DIR" ]; then
- git clone git://github.com/Themaister/RetroArch.git "$RetroArch_DIR"
+ git clone git://github.com/libretro/RetroArch.git "$RetroArch_DIR"
cd "$RetroArch_DIR"
else
cd "$RetroArch_DIR"
diff --git a/retroarch.c b/retroarch.c
index 8c1ceed1cd..db8231a93c 100644
--- a/retroarch.c
+++ b/retroarch.c
@@ -45,10 +45,6 @@
#include "msvc/msvc_compat.h"
#endif
-#if defined(RARCH_CONSOLE) && !defined(RARCH_PERFORMANCE_MODE)
-#define RARCH_PERFORMANCE_MODE
-#endif
-
// To avoid continous switching if we hold the button down, we require that the button must go from pressed,
// unpressed back to pressed to be able to toggle between then.
static void check_fast_forward_button(void)
@@ -465,7 +461,7 @@ size_t audio_sample_batch(const int16_t *data, size_t frames)
#ifdef HAVE_OVERLAY
static inline void input_poll_overlay(void)
{
- driver.overlay_state = 0;
+ memset(&driver.overlay_state, 0, sizeof(driver.overlay_state));
unsigned device = input_overlay_full_screen(driver.overlay) ?
RARCH_DEVICE_POINTER_SCREEN : RETRO_DEVICE_POINTER;
@@ -480,7 +476,15 @@ static inline void input_poll_overlay(void)
int16_t y = input_input_state_func(NULL, 0,
device, i, RETRO_DEVICE_ID_POINTER_Y);
- driver.overlay_state |= input_overlay_poll(driver.overlay, x, y);
+ input_overlay_state_t polled_data;
+ input_overlay_poll(driver.overlay, &polled_data, x, y);
+
+ driver.overlay_state.buttons |= polled_data.buttons;
+
+ for (unsigned j = 0; j < 4; j ++)
+ if (driver.overlay_state.analog[j] == 0)
+ driver.overlay_state.analog[j] = polled_data.analog[j];
+
polled = true;
}
@@ -547,7 +551,13 @@ static int16_t input_state(unsigned port, unsigned device, unsigned index, unsig
#ifdef HAVE_OVERLAY
if (device == RETRO_DEVICE_JOYPAD && port == 0)
- res |= driver.overlay_state & (UINT64_C(1) << id) ? 1 : 0;
+ res |= driver.overlay_state.buttons & (UINT64_C(1) << id) ? 1 : 0;
+ else if (device == RETRO_DEVICE_ANALOG && port == 0)
+ {
+ unsigned base = (index == RETRO_DEVICE_INDEX_ANALOG_RIGHT) ? 2 : 0;
+ base += (id == RETRO_DEVICE_ID_ANALOG_Y) ? 1 : 0;
+ res += driver.overlay_state.analog[base];
+ }
#endif
// Don't allow turbo for D-pad.
@@ -1424,7 +1434,7 @@ void rarch_init_rewind(void)
if (!g_settings.rewind_enable || g_extern.state_manager)
return;
- if (g_extern.system.audio_callback)
+ if (g_extern.system.audio_callback.callback)
{
RARCH_ERR("Implementation uses threaded audio. Cannot use rewind.\n");
return;
@@ -1882,14 +1892,22 @@ void rarch_load_state(void)
else
snprintf(load_path, sizeof(load_path), "%s", g_extern.savestate_name);
+ size_t size = pretro_serialize_size();
char msg[512];
- if (load_state(load_path))
- snprintf(msg, sizeof(msg), "Loaded state from slot #%u.", g_extern.state_slot);
+
+ if (size)
+ {
+ if (load_state(load_path))
+ snprintf(msg, sizeof(msg), "Loaded state from slot #%u.", g_extern.state_slot);
+ else
+ snprintf(msg, sizeof(msg), "Failed to load state from \"%s\".", load_path);
+ }
else
- snprintf(msg, sizeof(msg), "Failed to load state from \"%s\".", load_path);
+ strlcpy(msg, "Core does not support save states.", sizeof(msg));
msg_queue_clear(g_extern.msg_queue);
msg_queue_push(g_extern.msg_queue, msg, 2, 180);
+ RARCH_LOG("%s\n", msg);
}
void rarch_save_state(void)
@@ -1904,14 +1922,22 @@ void rarch_save_state(void)
else
snprintf(save_path, sizeof(save_path), "%s", g_extern.savestate_name);
+ size_t size = pretro_serialize_size();
char msg[512];
- if (save_state(save_path))
- snprintf(msg, sizeof(msg), "Saved state to slot #%u.", g_extern.state_slot);
+
+ if (size)
+ {
+ if (save_state(save_path))
+ snprintf(msg, sizeof(msg), "Saved state to slot #%u.", g_extern.state_slot);
+ else
+ snprintf(msg, sizeof(msg), "Failed to save state to \"%s\".", save_path);
+ }
else
- snprintf(msg, sizeof(msg), "Failed to save state to \"%s\".", save_path);
+ strlcpy(msg, "Core does not support save states.", sizeof(msg));
msg_queue_clear(g_extern.msg_queue);
msg_queue_push(g_extern.msg_queue, msg, 2, 180);
+ RARCH_LOG("%s\n", msg);
}
// Save or load state here.
@@ -1935,7 +1961,6 @@ static void check_savestates(bool immutable)
}
}
-#if !defined(RARCH_PERFORMANCE_MODE)
void rarch_set_fullscreen(bool fullscreen)
{
g_settings.video.fullscreen = fullscreen;
@@ -1966,7 +1991,6 @@ static bool check_fullscreen(void)
was_pressed = pressed;
return toggle;
}
-#endif
void rarch_state_slot_increase(void)
{
@@ -2193,7 +2217,6 @@ static void check_movie(void)
}
#endif
-#if !defined(RARCH_PERFORMANCE_MODE)
static void check_pause(void)
{
static bool old_state = false;
@@ -2266,7 +2289,6 @@ static void check_oneshot(void)
g_extern.is_oneshot |= new_rewind_state && !old_rewind_state;
old_rewind_state = new_rewind_state;
}
-#endif
void rarch_game_reset(void)
{
@@ -2565,7 +2587,6 @@ static void check_dsp_config(void)
}
#endif
-#if !defined(RARCH_PERFORMANCE_MODE)
static void check_mute(void)
{
if (!g_extern.audio_active)
@@ -2628,7 +2649,6 @@ static void check_volume(void)
g_extern.audio_data.volume_gain = db_to_gain(g_extern.audio_data.volume_db);
}
-#endif
#ifdef HAVE_NETPLAY
static void check_netplay_flip(void)
@@ -2700,10 +2720,8 @@ static void do_state_checks(void)
#if defined(HAVE_SCREENSHOTS) && !defined(_XBOX)
check_screenshot();
#endif
-#if !defined(RARCH_PERFORMANCE_MODE)
check_mute();
check_volume();
-#endif
check_turbo();
@@ -2719,7 +2737,6 @@ static void do_state_checks(void)
if (!g_extern.netplay)
{
#endif
-#if !defined(RARCH_PERFORMANCE_MODE)
check_pause();
check_oneshot();
@@ -2728,7 +2745,6 @@ static void do_state_checks(void)
if (g_extern.is_paused && !g_extern.is_oneshot)
return;
-#endif
check_fast_forward_button();
@@ -2759,9 +2775,7 @@ static void do_state_checks(void)
else
{
check_netplay_flip();
-#if !defined(RARCH_PERFORMANCE_MODE)
check_fullscreen();
-#endif
}
#endif
}
@@ -3059,6 +3073,12 @@ bool rarch_main_iterate(void)
if (check_enter_rgui())
return false; // Enter menu, don't exit.
+ if (g_extern.exec)
+ {
+ g_extern.exec = false;
+ return false;
+ }
+
#ifdef HAVE_COMMAND
if (driver.command)
rarch_cmd_pre_frame(driver.command);
diff --git a/retroarch.cfg b/retroarch.cfg
index 0e09db086e..29494888c1 100644
--- a/retroarch.cfg
+++ b/retroarch.cfg
@@ -89,6 +89,11 @@
# Maximum is 3.
# video_hard_sync_frames = 0
+# Inserts a black frame inbetween frames.
+# Useful for 120 Hz monitors who want to play 60 Hz material with eliminated ghosting.
+# video_refresh_rate should still be configured as if it is a 60 Hz monitor (divide refresh rate by 2).
+# video_black_frame_insertion = false
+
# Use threaded video driver. Using this might improve performance at possible cost of latency and more video stuttering.
# video_threaded = false
@@ -115,7 +120,7 @@
# Forces cropping of overscanned frames.
# Exact behavior of this option is implementation specific.
-# video_crop_overscan = false
+# video_crop_overscan = true
# Path to shader. Shader can be either Cg, CGP (Cg preset) or XML/GLSL format if support is enabled.
# video_shader = "/path/to/shader.{cg,cgp,shader}"
@@ -210,6 +215,12 @@
# Path to input overlay
# input_overlay =
+# Overlay opacity
+# input_overlay_opacity = 1.0
+
+# Overlay scale
+# input_overlay_scale = 1.0
+
# Enable input auto-detection. Will attempt to autoconfigure
# joypads, Plug-and-Play style.
# input_autodetect_enable = true
diff --git a/settings.c b/settings.c
index 4cfc84e2da..4cad7763cd 100644
--- a/settings.c
+++ b/settings.c
@@ -67,6 +67,8 @@ const char *config_get_default_audio(void)
return "ps3";
case AUDIO_WII:
return "gx";
+ case AUDIO_RWEBAUDIO:
+ return "rwebaudio";
case AUDIO_NULL:
return "null";
default:
@@ -137,6 +139,8 @@ const char *config_get_default_input(void)
return "apple_input";
case INPUT_QNX:
return "qnx_input";
+ case INPUT_RWEBINPUT:
+ return "rwebinput";
case INPUT_NULL:
return "null";
default:
@@ -168,6 +172,8 @@ void config_set_defaults(void)
g_settings.video.vsync = vsync;
g_settings.video.hard_sync = hard_sync;
g_settings.video.hard_sync_frames = hard_sync_frames;
+ g_settings.video.black_frame_insertion = black_frame_insertion;
+ g_settings.video.swap_interval = swap_interval;
g_settings.video.threaded = video_threaded;
g_settings.video.smooth = video_smooth;
g_settings.video.force_aspect = force_aspect;
@@ -196,6 +202,7 @@ void config_set_defaults(void)
g_settings.audio.enable = audio_enable;
g_settings.audio.out_rate = out_rate;
+ g_settings.audio.block_frames = 0;
g_settings.audio.in_rate = out_rate;
if (audio_device)
strlcpy(g_settings.audio.device, audio_device, sizeof(g_settings.audio.device));
@@ -490,6 +497,10 @@ bool config_load_file(const char *path)
if (g_settings.video.hard_sync_frames > 3)
g_settings.video.hard_sync_frames = 3;
+ CONFIG_GET_BOOL(video.black_frame_insertion, "video_black_frame_insertion");
+ CONFIG_GET_INT(video.swap_interval, "video_swap_interval");
+ g_settings.video.swap_interval = max(g_settings.video.swap_interval, 1);
+ g_settings.video.swap_interval = min(g_settings.video.swap_interval, 4);
CONFIG_GET_BOOL(video.threaded, "video_threaded");
CONFIG_GET_BOOL(video.smooth, "video_smooth");
CONFIG_GET_BOOL(video.force_aspect, "video_force_aspect");
@@ -628,6 +639,7 @@ bool config_load_file(const char *path)
// Audio settings.
CONFIG_GET_BOOL(audio.enable, "audio_enable");
CONFIG_GET_INT(audio.out_rate, "audio_out_rate");
+ CONFIG_GET_INT(audio.block_frames, "audio_block_frames");
CONFIG_GET_STRING(audio.device, "audio_device");
CONFIG_GET_INT(audio.latency, "audio_latency");
CONFIG_GET_BOOL(audio.sync, "audio_sync");
@@ -664,8 +676,9 @@ bool config_load_file(const char *path)
if (!strcmp(g_extern.overlay_dir, "default"))
*g_extern.overlay_dir = '\0';
- CONFIG_GET_FLOAT(input.overlay_opacity, "overlay_opacity");
- CONFIG_GET_FLOAT(input.overlay_scale, "overlay_scale");
+ CONFIG_GET_PATH(input.overlay, "input_overlay");
+ CONFIG_GET_FLOAT(input.overlay_opacity, "input_overlay_opacity");
+ CONFIG_GET_FLOAT(input.overlay_scale, "input_overlay_scale");
#endif
CONFIG_GET_BOOL(rewind_enable, "rewind_enable");
@@ -702,9 +715,6 @@ bool config_load_file(const char *path)
CONFIG_GET_INT(input.turbo_period, "input_turbo_period");
CONFIG_GET_INT(input.turbo_duty_cycle, "input_duty_cycle");
- CONFIG_GET_PATH(input.overlay, "input_overlay");
- CONFIG_GET_FLOAT(input.overlay_opacity, "input_overlay_opacity");
- CONFIG_GET_FLOAT(input.overlay_scale, "input_overlay_scale");
CONFIG_GET_BOOL(input.debug_enable, "input_debug_enable");
CONFIG_GET_BOOL(input.autodetect_enable, "input_autodetect_enable");
@@ -970,12 +980,17 @@ bool config_save_file(const char *path)
config_set_string(conf, "video_shader", g_settings.video.shader_path);
config_set_bool(conf, "video_shader_enable", g_settings.video.shader_enable);
config_set_float(conf, "video_aspect_ratio", g_settings.video.aspect_ratio);
+ config_set_float(conf, "video_xscale", g_settings.video.xscale);
+ config_set_float(conf, "video_yscale", g_settings.video.yscale);
+ config_set_bool(conf, "video_crop_overscan", g_settings.video.crop_overscan);
config_set_bool(conf, "video_scale_integer", g_settings.video.scale_integer);
config_set_bool(conf, "video_smooth", g_settings.video.smooth);
config_set_float(conf, "video_refresh_rate", g_settings.video.refresh_rate);
config_set_bool(conf, "video_vsync", g_settings.video.vsync);
config_set_bool(conf, "video_hard_sync", g_settings.video.hard_sync);
config_set_int(conf, "video_hard_sync_frames", g_settings.video.hard_sync_frames);
+ config_set_bool(conf, "video_black_frame_insertion", g_settings.video.black_frame_insertion);
+ config_set_int(conf, "video_swap_interval", g_settings.video.swap_interval);
config_set_int(conf, "aspect_ratio_index", g_settings.video.aspect_ratio_idx);
config_set_string(conf, "audio_device", g_settings.audio.device);
config_set_bool(conf, "audio_rate_control", g_settings.audio.rate_control);
@@ -1014,8 +1029,9 @@ bool config_save_file(const char *path)
else
config_set_string(conf, "overlay_directory", "default");
- config_set_float(conf, "overlay_opacity", g_settings.input.overlay_opacity);
- config_set_float(conf, "overlay_scale", g_settings.input.overlay_scale);
+ config_set_string(conf, "input_overlay", g_settings.input.overlay);
+ config_set_float(conf, "input_overlay_opacity", g_settings.input.overlay_opacity);
+ config_set_float(conf, "input_overlay_scale", g_settings.input.overlay_scale);
#endif
#ifdef ANDROID
@@ -1081,6 +1097,8 @@ bool config_save_file(const char *path)
config_set_int(conf, cfg, g_settings.input.dpad_emulation[i]);
snprintf(cfg, sizeof(cfg), "input_device_p%u", i + 1);
config_set_int(conf, cfg, g_settings.input.device[i]);
+ snprintf(cfg, sizeof(cfg), "input_player%u_joypad_index", i + 1);
+ config_set_int(conf, cfg, g_settings.input.joypad_map[i]);
}
config_file_write(conf, path);
diff --git a/tools/cg2glsl.py b/tools/cg2glsl.py
index aa5b279a45..7f2f341f29 100755
--- a/tools/cg2glsl.py
+++ b/tools/cg2glsl.py
@@ -537,7 +537,7 @@ def preprocess_vertex(source_data):
input_data = source_data.split('\n')
ret = []
for line in input_data:
- if 'uniform float4x4' in line:
+ if ('uniform' in line) and (('float4x4' in line) or ('half4x4' in line)):
ret.append('#pragma pack_matrix(column_major)\n')
ret.append(line)
ret.append('#pragma pack_matrix(row_major)\n')