Merge branch 'master' of https://github.com/libretro/RetroArch into emscripten

Conflicts:
	gfx/gl.c
This commit is contained in:
ToadKing 2013-08-25 15:37:16 -04:00
commit 87844cc486
195 changed files with 13864 additions and 4975 deletions

11
.gitignore vendored
View File

@ -49,3 +49,14 @@ DerivedData
apple/tmp
apple/modules/*.dylib
apple/*.mobileprovision
/Cg/
/GL/
/SDL/
/ffmpeg/
/freetype2/
/ft2build.h
/iconv.h
/libxml2/
/phoenix/
/python/
/rsound.h

11
.project Normal file
View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>RetroArch_</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
</buildSpec>
<natures>
</natures>
</projectDescription>

View File

@ -20,6 +20,9 @@ Daniel De Matteis - <libretro@gmail.com>
- Blackberry 10/Playbook port
- iOS port patches
Tobias Jakobi - <TBA>
- OMAP graphics driver
Jason Fetters - <TBA>
- Phoenix Java frontend
- Android port patches

View File

@ -3,6 +3,7 @@ include config.mk
TARGET = retroarch tools/retroarch-joyconfig tools/retrolaunch/retrolaunch
OBJ = frontend/frontend.o \
frontend/frontend_context.o \
retroarch.o \
file.o \
file_path.o \
@ -92,7 +93,7 @@ ifeq ($(HAVE_RGUI), 1)
endif
ifeq ($(HAVE_THREADS), 1)
OBJ += autosave.o thread.o gfx/thread_wrapper.o
OBJ += autosave.o thread.o gfx/thread_wrapper.o audio/thread_wrapper.o
ifeq ($(findstring Haiku,$(OS)),)
LIBS += -lpthread
endif
@ -185,13 +186,18 @@ ifeq ($(HAVE_SDL), 1)
LIBS += $(SDL_LIBS)
endif
ifeq ($(HAVE_OMAP), 1)
OBJ += gfx/omap_gfx.o gfx/fbdev.o
endif
ifeq ($(HAVE_OPENGL), 1)
OBJ += gfx/gl.o \
gfx/gfx_context.o \
gfx/fonts/gl_font.o \
gfx/fonts/gl_raster_font.o \
gfx/math/matrix.o \
gfx/state_tracker.o
gfx/state_tracker.o \
gfx/glsym/rglgen.o
ifeq ($(HAVE_KMS), 1)
OBJ += gfx/context/drm_egl_ctx.o
@ -218,12 +224,14 @@ ifeq ($(HAVE_OPENGL), 1)
ifeq ($(HAVE_GLES), 1)
LIBS += -lGLESv2
DEFINES += -DHAVE_OPENGLES -DHAVE_OPENGLES2
OBJ += gfx/glsym/glsym_es2.o
else
DEFINES += -DHAVE_GL_SYNC
OBJ += gfx/glsym/glsym_gl.o
ifeq ($(OSX), 1)
LIBS += -framework OpenGL
else
LIBS += -lGL
DEFINES += -DHAVE_GL_SYNC
endif
endif
@ -329,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)
@ -419,6 +432,7 @@ clean:
rm -f audio/*.o
rm -f conf/*.o
rm -f gfx/*.o
rm -f gfx/glsym/*.o
rm -f gfx/rpng/*.o
rm -f gfx/fonts/*.o
rm -f gfx/math/*.o

View File

@ -19,7 +19,7 @@ endif
STRIP = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-strip.exe
PPU_CFLAGS += -I. -D__CELLOS_LV2__ -DIS_SALAMANDER -DRARCH_CONSOLE -DHAVE_SYSUTILS -DHAVE_SYSMODULES -DHAVE_RARCH_EXEC
PPU_SRCS = frontend/frontend_salamander.c file_path.c compat/compat.c conf/config_file.c
PPU_SRCS = frontend/frontend_salamander.c frontend/frontend_context.c file_path.c compat/compat.c conf/config_file.c
ifeq ($(HAVE_LOGGER), 1)
PPU_CFLAGS += -DHAVE_LOGGER -Iconsole/logger

View File

@ -92,7 +92,7 @@ endif
RSXGL_DEFINES = -D__RSX__ -DGL3_PROTOTYPES
SHARED_FLAGS := -DHAVE_FILEBROWSER $(RSXGL_DEFINES) -DHAVE_OPENGL -DHAVE_EGL -DHAVE_OPENGL_MODERN -DHAVE_GLSL -DHAVE_VID_CONTEXT -DHAVE_FBO -DHAVE_MOUSE -DRARCH_CONSOLE -DHAVE_ZLIB -DWANT_MINIZ -DHAVE_RARCH_MAIN_WRAP -DHAVE_RARCH_MAIN_IMPLEMENTATION -DHAVE_SYSMODULES -DHAVE_SYSUTILS -DHAVE_GRIFFIN=1 -DHAVE_NETPLAY=1 -DHAVE_SOCKET_LEGACY=1 -DPACKAGE_VERSION=\"0.9.8\" -DPC_DEVELOPMENT_IP_ADDRESS=\"$(PC_DEVELOPMENT_IP_ADDRESS)\" -DPC_DEVELOPMENT_UDP_PORT=$(PC_DEVELOPMENT_UDP_PORT) -Wno-char-subscripts
SHARED_FLAGS := -DHAVE_FILEBROWSER $(RSXGL_DEFINES) -DHAVE_OPENGL -DHAVE_EGL -DHAVE_OPENGL_MODERN -DHAVE_GLSL -DHAVE_VID_CONTEXT -DHAVE_FBO -DHAVE_MOUSE -DRARCH_CONSOLE -DHAVE_ZLIB -DWANT_MINIZ -DHAVE_RARCH_MAIN_WRAP -DHAVE_RARCH_MAIN_IMPLEMENTATION -DHAVE_SYSMODULES -DHAVE_SYSUTILS -DHAVE_GRIFFIN=1 -DHAVE_NETPLAY=1 -DHAVE_SOCKET_LEGACY=1 -DPC_DEVELOPMENT_IP_ADDRESS=\"$(PC_DEVELOPMENT_IP_ADDRESS)\" -DPC_DEVELOPMENT_UDP_PORT=$(PC_DEVELOPMENT_UDP_PORT) -Wno-char-subscripts
CFLAGS += -std=gnu99 $(SHARED_FLAGS)
CXXFLAGS += $(SHARED_FLAGS)

View File

@ -39,7 +39,7 @@ LIBS := -lfat -lwiiuse -logc -lbte
APP_BOOTER_DIR = wii/app_booter
OBJ = frontend/frontend_salamander.o file_path.o compat/compat.o conf/config_file.o $(APP_BOOTER_DIR)/app_booter.binobj
OBJ = frontend/frontend_salamander.o frontend/frontend_context.o file_path.o compat/compat.o conf/config_file.o $(APP_BOOTER_DIR)/app_booter.binobj
ifeq ($(HAVE_LOGGER), 1)
CFLAGS += -DHAVE_LOGGER
@ -53,7 +53,7 @@ CFLAGS += -DHAVE_FILE_LOGGER
CFLAGS += -Iconsole/logger
endif
CFLAGS += -std=gnu99 -DIS_SALAMANDER -DRARCH_CONSOLE -DHAVE_RARCH_EXEC -DGEKKO -DPACKAGE_VERSION=\"0.9.8\" -Wno-char-subscripts
CFLAGS += -std=gnu99 -DIS_SALAMANDER -DRARCH_CONSOLE -DHAVE_RARCH_EXEC -DGEKKO -Wno-char-subscripts
ifeq ($(DEBUG), 1)
CFLAGS += -O0 -g

View File

@ -2,6 +2,7 @@ TARGET = retroarch.exe
JTARGET = tools/retroarch-joyconfig.exe
OBJ = frontend/frontend.o \
frontend/frontend_context.o \
retroarch.o \
file.o \
file_path.o \
@ -53,6 +54,7 @@ HAVE_DINPUT = 1
HAVE_XAUDIO = 1
HAVE_DSOUND = 1
HAVE_OPENGL = 1
HAVE_FBO = 1
HAVE_DYLIB = 1
HAVE_D3D9 = 1
HAVE_NETPLAY = 1
@ -68,7 +70,6 @@ ifeq ($(SLIM),)
HAVE_FREETYPE = 1
HAVE_ZLIB = 1
HAVE_RSOUND = 1
HAVE_FBO = 1
HAVE_CG = 1
HAVE_PYTHON = 1
HAVE_FFMPEG = 1
@ -77,7 +78,7 @@ endif
libretro ?= -lretro
LIBS = -lm
DEFINES = -I. -DHAVE_SCREENSHOTS -DHAVE_BSV_MOVIE -DPACKAGE_VERSION=\"0.9.9.3\"
DEFINES = -I. -DHAVE_SCREENSHOTS -DHAVE_BSV_MOVIE
LDFLAGS = -L. -static-libgcc
ifeq ($(TDM_GCC),)
@ -108,12 +109,12 @@ ifeq ($(HAVE_SDL), 1)
endif
ifeq ($(HAVE_THREADS), 1)
OBJ += autosave.o thread.o gfx/thread_wrapper.o
OBJ += autosave.o thread.o gfx/thread_wrapper.o audio/thread_wrapper.o
DEFINES += -DHAVE_THREADS
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/wgl_ctx.o gfx/shader_glsl.o
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/wgl_ctx.o gfx/shader_glsl.o gfx/glsym/rglgen.o gfx/glsym/glsym_gl.o
DEFINES += -DHAVE_OPENGL -DHAVE_OVERLAY -DHAVE_GLSL -DHAVE_GL_SYNC
LIBS += -lopengl32 -lgdi32 -lcomdlg32
endif
@ -236,6 +237,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)
@ -286,6 +292,7 @@ clean:
rm -f conf/*.o
rm -f gfx/scaler/*.o
rm -f gfx/*.o
rm -f gfx/glsym/*.o
rm -f gfx/d3d9/*.o
rm -f gfx/context/*.o
rm -f gfx/math/*.o
@ -299,21 +306,21 @@ clean:
rm -f tools/*.o
dist_x86: all
zip -r retroarch-win32-0.9.9.zip $(TARGET) $(JTARGET) retroarch.cfg
zip -r retroarch-win32-0.9.9.4.zip $(TARGET) $(JTARGET) retroarch.cfg
dist_x86_64: all
zip -r retroarch-win64-0.9.9.zip $(TARGET) $(JTARGET) retroarch.cfg
zip -r retroarch-win64-0.9.9.4.zip $(TARGET) $(JTARGET) retroarch.cfg
libs_x86:
wget https://github.com/downloads/Themaister/RetroArch/RetroArch-win32-libs.zip --no-check-certificate
wget http://themaister.net/retroarch-dl/RetroArch-win32-libs.zip
unzip RetroArch-win32-libs.zip
wget https://github.com/downloads/Themaister/RetroArch/RetroArch-win32-headers.zip --no-check-certificate
wget http://themaister.net/retroarch-dl/RetroArch-win32-headers.zip
unzip RetroArch-win32-headers.zip
libs_x86_64:
wget https://github.com/downloads/Themaister/RetroArch/RetroArch-win64-libs.zip --no-check-certificate
wget http://themaister.net/retroarch-dl/RetroArch-win64-libs.zip
unzip RetroArch-win64-libs.zip
wget https://github.com/downloads/Themaister/RetroArch/RetroArch-win64-headers.zip --no-check-certificate
wget http://themaister.net/retroarch-dl/RetroArch-win64-headers.zip
unzip RetroArch-win64-headers.zip
.PHONY: all install uninstall clean dist_x86 dist_x86_64 libs_x86 libs_x86_64

View File

@ -29,9 +29,9 @@
typedef struct
{
float dzone_min;
float dzone_max;
} dpad_values_t;
int16_t lx, ly;
int16_t rx, ry;
} analog_t;
#define PRESSED_UP(x, y) ((y <= dzone_min))
#define PRESSED_DOWN(x, y) ((y >= dzone_max))
@ -42,8 +42,7 @@ static unsigned pads_connected;
static int state_device_ids[MAX_PADS];
static uint64_t state[MAX_PADS];
static uint64_t keycode_lut[LAST_KEYCODE];
dpad_values_t dpad_state[MAX_PADS];
analog_t analog_state[MAX_PADS];
struct input_pointer
{
@ -61,10 +60,12 @@ enum
AXIS_Z = 11,
AXIS_RZ = 14,
AXIS_HAT_X = 15,
AXIS_HAT_Y = 16
AXIS_HAT_Y = 16,
AXIS_LTRIGGER = 17,
AXIS_RTRIGGER = 18,
};
void (*engine_handle_dpad)(AInputEvent*, size_t, int, char*, size_t, int, bool);
void (*engine_handle_dpad)(AInputEvent*, size_t, int, char*, size_t, int, bool, unsigned);
extern float AMotionEvent_getAxisValue(const AInputEvent* motion_event,
int32_t axis, size_t pointer_index);
@ -183,21 +184,25 @@ void engine_handle_cmd(void)
static void engine_handle_dpad_default(AInputEvent *event,
size_t motion_pointer, int state_id, char *msg, size_t msg_sizeof,
int source, bool debug_enable)
int source, bool debug_enable, unsigned emulation)
{
uint64_t *state_cur = &state[state_id];
float dzone_min = dpad_state[state_id].dzone_min;
float dzone_max = dpad_state[state_id].dzone_max;
float dzone_min = -g_settings.input.axis_threshold;
float dzone_max = g_settings.input.axis_threshold;
float x = AMotionEvent_getX(event, motion_pointer);
float y = AMotionEvent_getY(event, motion_pointer);
*state_cur &= ~((1ULL << RETRO_DEVICE_ID_JOYPAD_LEFT) |
(1ULL << RETRO_DEVICE_ID_JOYPAD_RIGHT) | (1ULL << RETRO_DEVICE_ID_JOYPAD_UP) |
(1ULL << RETRO_DEVICE_ID_JOYPAD_DOWN));
*state_cur |= PRESSED_LEFT(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_LEFT) : 0;
*state_cur |= PRESSED_RIGHT(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_RIGHT) : 0;
*state_cur |= PRESSED_UP(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_UP) : 0;
*state_cur |= PRESSED_DOWN(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_DOWN) : 0;
if (emulation == ANALOG_DPAD_LSTICK)
{
*state_cur |= PRESSED_LEFT(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_LEFT) : 0;
*state_cur |= PRESSED_RIGHT(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_RIGHT) : 0;
*state_cur |= PRESSED_UP(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_UP) : 0;
*state_cur |= PRESSED_DOWN(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_DOWN) : 0;
}
if (debug_enable)
snprintf(msg, msg_sizeof, "Pad %d : x = %.2f, y = %.2f, src %d.\n",
@ -206,31 +211,34 @@ static void engine_handle_dpad_default(AInputEvent *event,
static void engine_handle_dpad_getaxisvalue(AInputEvent *event,
size_t motion_pointer, int state_id, char *msg, size_t msg_sizeof, int source,
bool debug_enable)
bool debug_enable, unsigned emulation)
{
uint64_t *state_cur = &state[state_id];
float dzone_min = dpad_state[state_id].dzone_min;
float dzone_max = dpad_state[state_id].dzone_max;
float dzone_min = -g_settings.input.axis_threshold;
float dzone_max = g_settings.input.axis_threshold;
float x = AMotionEvent_getAxisValue(event, AXIS_X, motion_pointer);
float y = AMotionEvent_getAxisValue(event, AXIS_Y, motion_pointer);
float z = AMotionEvent_getAxisValue(event, AXIS_Z, motion_pointer);
float rz = AMotionEvent_getAxisValue(event, AXIS_RZ, motion_pointer);
float hatx = AMotionEvent_getAxisValue(event, AXIS_HAT_X, motion_pointer);
float haty = AMotionEvent_getAxisValue(event, AXIS_HAT_Y, motion_pointer);
float ltrig = AMotionEvent_getAxisValue(event, AXIS_LTRIGGER, motion_pointer);
float rtrig = AMotionEvent_getAxisValue(event, AXIS_RTRIGGER, motion_pointer);
*state_cur &= ~((1ULL << RETRO_DEVICE_ID_JOYPAD_LEFT) |
(1ULL << RETRO_DEVICE_ID_JOYPAD_L2) | (1ULL << RETRO_DEVICE_ID_JOYPAD_R2) |
(1ULL << RETRO_DEVICE_ID_JOYPAD_RIGHT) | (1ULL << RETRO_DEVICE_ID_JOYPAD_UP) |
(1ULL << RETRO_DEVICE_ID_JOYPAD_DOWN));
/* On some devices the dpad sends AXIS_HAT_X / AXIS_HAT_Y events, use those first if the returned values are nonzero */
if (fabs(hatx) > 0.0001 || fabs(haty) > 0.0001)
if (fabsf(hatx) > 0.0001f || fabsf(haty) > 0.0001f)
{
*state_cur |= PRESSED_LEFT(hatx, haty) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_LEFT) : 0;
*state_cur |= PRESSED_RIGHT(hatx, haty) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_RIGHT) : 0;
*state_cur |= PRESSED_UP(hatx, haty) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_UP) : 0;
*state_cur |= PRESSED_DOWN(hatx, haty) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_DOWN) : 0;
}
else
else if (emulation == ANALOG_DPAD_LSTICK)
{
*state_cur |= PRESSED_LEFT(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_LEFT) : 0;
*state_cur |= PRESSED_RIGHT(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_RIGHT) : 0;
@ -238,6 +246,19 @@ static void engine_handle_dpad_getaxisvalue(AInputEvent *event,
*state_cur |= PRESSED_DOWN(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_DOWN) : 0;
}
if (ltrig > 0.5f)
*state_cur |= 1ULL << RETRO_DEVICE_ID_JOYPAD_L2;
if (rtrig > 0.5f)
*state_cur |= 1ULL << RETRO_DEVICE_ID_JOYPAD_R2;
if (emulation == ANALOG_DPAD_DUALANALOG)
{
analog_state[state_id].lx = x * 0x7fff;
analog_state[state_id].ly = y * 0x7fff;
analog_state[state_id].rx = z * 0x7fff;
analog_state[state_id].ry = rz * 0x7fff;
}
if (debug_enable)
snprintf(msg, msg_sizeof, "Pad %d : x %.2f, y %.2f, z %.2f, rz %.2f, src %d.\n",
state_id, x, y, z, rz, source);
@ -248,7 +269,7 @@ static void *android_input_init(void)
unsigned i, j, k;
pads_connected = 0;
for(j = 0; j < LAST_KEYCODE; j++)
for (j = 0; j < LAST_KEYCODE; j++)
keycode_lut[j] = 0;
if (!g_settings.input.autodetect_enable)
@ -267,9 +288,9 @@ static void *android_input_init(void)
}
}
for(i = 0; i < MAX_PADS; i++)
for (i = 0; i < MAX_PADS; i++)
{
for(j = 0; j < RARCH_FIRST_META_KEY; j++)
for (j = 0; j < RARCH_FIRST_META_KEY; j++)
{
g_settings.input.binds[i][j].id = i;
g_settings.input.binds[i][j].joykey = 0;
@ -292,8 +313,6 @@ static void *android_input_init(void)
g_settings.input.binds[i][RETRO_DEVICE_ID_JOYPAD_L3].joykey = (1ULL << RETRO_DEVICE_ID_JOYPAD_L3);
g_settings.input.binds[i][RETRO_DEVICE_ID_JOYPAD_R3].joykey = (1ULL << RETRO_DEVICE_ID_JOYPAD_R3);
dpad_state[i].dzone_min = -0.99f;
dpad_state[i].dzone_max = 0.99f;
g_settings.input.dpad_emulation[i] = ANALOG_DPAD_LSTICK;
}
@ -351,6 +370,7 @@ static void android_input_set_keybinds(void *data, unsigned device,
strlcpy(g_settings.input.device_names[port], "Logitech Rumblepad 2",
sizeof(g_settings.input.device_names[port]));
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_DUALANALOG;
keycode_lut[AKEYCODE_BUTTON_2] |= ((RETRO_DEVICE_ID_JOYPAD_B+1) << shift);
keycode_lut[AKEYCODE_BUTTON_1] |= ((RETRO_DEVICE_ID_JOYPAD_Y+1) << shift);
keycode_lut[AKEYCODE_BUTTON_9] |= ((RETRO_DEVICE_ID_JOYPAD_SELECT+1) << shift);
@ -403,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]));
@ -482,9 +502,6 @@ static void android_input_set_keybinds(void *data, unsigned device,
g_settings.input.device[port] = device;
strlcpy(g_settings.input.device_names[port], "TTT THT Arcade",
sizeof(g_settings.input.device_names[port]));
dpad_state[id].dzone_min = -2.00f;
dpad_state[id].dzone_max = 1.00f;
/* same as Rumblepad 2 - merge? */
//keycode_lut[AKEYCODE_BUTTON_7] |= ((RETRO_DEVICE_ID_JOYPAD_L2+1) << shift);
@ -623,8 +640,6 @@ static void android_input_set_keybinds(void *data, unsigned device,
g_settings.input.device[port] = device;
strlcpy(g_settings.input.device_names[port], "Huijia USB SNES",
sizeof(g_settings.input.device_names[port]));
dpad_state[id].dzone_min = -1.00f;
dpad_state[id].dzone_max = 1.00f;
keycode_lut[AKEYCODE_BUTTON_3] |= ((RETRO_DEVICE_ID_JOYPAD_B+1) << shift);
keycode_lut[AKEYCODE_BUTTON_4] |= ((RETRO_DEVICE_ID_JOYPAD_Y+1) << shift);
@ -639,8 +654,6 @@ static void android_input_set_keybinds(void *data, unsigned device,
g_settings.input.device[port] = device;
strlcpy(g_settings.input.device_names[port], "Super Smartjoy",
sizeof(g_settings.input.device_names[port]));
dpad_state[id].dzone_min = -1.00f;
dpad_state[id].dzone_max = 1.00f;
keycode_lut[AKEYCODE_BUTTON_3] |= ((RETRO_DEVICE_ID_JOYPAD_B+1) << shift);
keycode_lut[AKEYCODE_BUTTON_4] |= ((RETRO_DEVICE_ID_JOYPAD_Y+1) << shift);
@ -708,7 +721,9 @@ static void android_input_set_keybinds(void *data, unsigned device,
strlcpy(g_settings.input.device_names[port], "Xbox",
sizeof(g_settings.input.device_names[port]));
/* TODO: left and right triggers for Xbox 1*/
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_DUALANALOG;
keycode_lut[AKEYCODE_BUTTON_MODE] |= ((RARCH_MENU_TOGGLE + 1) << shift);
keycode_lut[AKEYCODE_BACK] |= ((RETRO_DEVICE_ID_JOYPAD_SELECT+1) << shift);
keycode_lut[AKEYCODE_BUTTON_SELECT] |= ((RETRO_DEVICE_ID_JOYPAD_SELECT+1) << shift);
keycode_lut[AKEYCODE_BUTTON_START] |= ((RETRO_DEVICE_ID_JOYPAD_START+1) << shift);
keycode_lut[AKEYCODE_BUTTON_THUMBL] |= ((RETRO_DEVICE_ID_JOYPAD_L3+1) << shift);
@ -725,6 +740,7 @@ static void android_input_set_keybinds(void *data, unsigned device,
strlcpy(g_settings.input.device_names[port], "WiseGroup PlayStation2",
sizeof(g_settings.input.device_names[port]));
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_DUALANALOG;
keycode_lut[AKEYCODE_BUTTON_13] |= ((RETRO_DEVICE_ID_JOYPAD_UP+1) << shift);
keycode_lut[AKEYCODE_BUTTON_15] |= ((RETRO_DEVICE_ID_JOYPAD_DOWN+1) << shift);
keycode_lut[AKEYCODE_BUTTON_16] |= ((RETRO_DEVICE_ID_JOYPAD_LEFT+1) << shift);
@ -823,52 +839,29 @@ static void android_input_set_keybinds(void *data, unsigned device,
keycode_lut[AKEYCODE_ESCAPE] |= ((RARCH_QUIT_KEY+1) << shift);
break;
case DEVICE_PLAYSTATION3_VERSION1:
g_settings.input.device[port] = device;
strlcpy(g_settings.input.device_names[port], "PlayStation3 Ver.1",
sizeof(g_settings.input.device_names[port]));
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_NONE;
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);
keycode_lut[AKEYCODE_DPAD_RIGHT] |= ((RETRO_DEVICE_ID_JOYPAD_RIGHT+1) << shift);
keycode_lut[AKEYCODE_BUTTON_A] |= ((RETRO_DEVICE_ID_JOYPAD_B+1) << shift);
keycode_lut[AKEYCODE_BUTTON_X] |= ((RETRO_DEVICE_ID_JOYPAD_Y+1) << shift);
keycode_lut[AKEYCODE_BUTTON_SELECT] |= ((RETRO_DEVICE_ID_JOYPAD_SELECT+1) << shift);
keycode_lut[AKEYCODE_BUTTON_START] |= ((RETRO_DEVICE_ID_JOYPAD_START+1) << shift);
keycode_lut[AKEYCODE_BUTTON_Y] |= ((RETRO_DEVICE_ID_JOYPAD_X+1) << shift);
keycode_lut[AKEYCODE_BUTTON_B] |= ((RETRO_DEVICE_ID_JOYPAD_A+1) << shift);
keycode_lut[AKEYCODE_BUTTON_L1] |= ((RETRO_DEVICE_ID_JOYPAD_L+1) << shift);
keycode_lut[AKEYCODE_BUTTON_R1] |= ((RETRO_DEVICE_ID_JOYPAD_R+1) << shift);
keycode_lut[AKEYCODE_BUTTON_L2] |= ((RETRO_DEVICE_ID_JOYPAD_L2+1) << shift);
keycode_lut[AKEYCODE_BUTTON_R2] |= ((RETRO_DEVICE_ID_JOYPAD_R2+1) << shift);
keycode_lut[AKEYCODE_BUTTON_THUMBL] |= ((RETRO_DEVICE_ID_JOYPAD_L3+1) << shift);
keycode_lut[AKEYCODE_BUTTON_THUMBR] |= ((RETRO_DEVICE_ID_JOYPAD_R3+1) << shift);
keycode_lut[AKEYCODE_BUTTON_1] |= ((RARCH_MENU_TOGGLE+1) << shift);
break;
case DEVICE_PLAYSTATION3_VERSION2:
g_settings.input.device[port] = device;
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_NONE;
strlcpy(g_settings.input.device_names[port], "PlayStation3 Ver.2",
strlcpy(g_settings.input.device_names[port], "PlayStation3",
sizeof(g_settings.input.device_names[port]));
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_NONE;
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);
keycode_lut[AKEYCODE_DPAD_RIGHT] |= ((RETRO_DEVICE_ID_JOYPAD_RIGHT+1) << shift);
keycode_lut[AKEYCODE_BUTTON_1] |= ((RARCH_MENU_TOGGLE+1) << shift);
keycode_lut[AKEYCODE_BUTTON_A] |= ((RETRO_DEVICE_ID_JOYPAD_B+1) << shift);
keycode_lut[AKEYCODE_BUTTON_X] |= ((RETRO_DEVICE_ID_JOYPAD_Y+1) << shift);
keycode_lut[AKEYCODE_BUTTON_A] |= ((RETRO_DEVICE_ID_JOYPAD_Y+1) << shift);
keycode_lut[AKEYCODE_BUTTON_X] |= ((RETRO_DEVICE_ID_JOYPAD_B+1) << shift);
keycode_lut[AKEYCODE_BUTTON_SELECT] |= ((RETRO_DEVICE_ID_JOYPAD_SELECT+1) << shift);
keycode_lut[AKEYCODE_BUTTON_START] |= ((RETRO_DEVICE_ID_JOYPAD_START+1) << shift);
keycode_lut[AKEYCODE_BUTTON_Y] |= ((RETRO_DEVICE_ID_JOYPAD_X+1) << shift);
keycode_lut[AKEYCODE_BUTTON_B] |= ((RETRO_DEVICE_ID_JOYPAD_A+1) << shift);
keycode_lut[AKEYCODE_BUTTON_B] |= ((RETRO_DEVICE_ID_JOYPAD_X+1) << shift);
keycode_lut[AKEYCODE_BUTTON_Y] |= ((RETRO_DEVICE_ID_JOYPAD_A+1) << shift);
keycode_lut[AKEYCODE_BUTTON_L1] |= ((RETRO_DEVICE_ID_JOYPAD_L+1) << shift);
keycode_lut[AKEYCODE_BUTTON_R1] |= ((RETRO_DEVICE_ID_JOYPAD_R+1) << shift);
keycode_lut[AKEYCODE_BUTTON_L2] |= ((RETRO_DEVICE_ID_JOYPAD_L2+1) << shift);
keycode_lut[AKEYCODE_BUTTON_R2] |= ((RETRO_DEVICE_ID_JOYPAD_R2+1) << shift);
keycode_lut[AKEYCODE_BUTTON_THUMBL] |= ((RETRO_DEVICE_ID_JOYPAD_L3+1) << shift);
keycode_lut[AKEYCODE_BUTTON_THUMBR] |= ((RETRO_DEVICE_ID_JOYPAD_R3+1) << shift);
keycode_lut[AKEYCODE_BUTTON_1] |= ((RARCH_MENU_TOGGLE+1) << shift);
break;
case DEVICE_MOGA:
g_settings.input.device[port] = device;
@ -1045,8 +1038,6 @@ static void android_input_set_keybinds(void *data, unsigned device,
g_settings.input.device[port] = device;
strlcpy(g_settings.input.device_names[port], "Buffalo BGC FC801",
sizeof(g_settings.input.device_names[port]));
dpad_state[id].dzone_min = -1.00f;
dpad_state[id].dzone_max = 1.00f;
keycode_lut[AKEYCODE_BUTTON_1] |= ((RETRO_DEVICE_ID_JOYPAD_A+1) << shift);
keycode_lut[AKEYCODE_BUTTON_2] |= ((RETRO_DEVICE_ID_JOYPAD_B+1) << shift);
@ -1199,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);
@ -1323,6 +1315,22 @@ static void android_input_set_keybinds(void *data, unsigned device,
keycode_lut[AKEYCODE_DPAD_LEFT] |= ((RETRO_DEVICE_ID_JOYPAD_LEFT+1) << shift);
keycode_lut[AKEYCODE_DPAD_RIGHT]|= ((RETRO_DEVICE_ID_JOYPAD_RIGHT+1) << shift);
break;
case ICADE_PROFILE_IPEGA_PG9017_MODE2:
strlcpy(g_settings.input.device_names[port], "iPega PG-9017 (Mode2)",
sizeof(g_settings.input.device_names[port]));
keycode_lut[AKEYCODE_M] |= ((RETRO_DEVICE_ID_JOYPAD_Y+1) << shift);
keycode_lut[AKEYCODE_J] |= ((RETRO_DEVICE_ID_JOYPAD_B+1) << shift);
keycode_lut[AKEYCODE_K] |= ((RETRO_DEVICE_ID_JOYPAD_A+1) << shift);
keycode_lut[AKEYCODE_I] |= ((RETRO_DEVICE_ID_JOYPAD_X+1) << shift);
keycode_lut[AKEYCODE_Q] |= ((RETRO_DEVICE_ID_JOYPAD_L+1) << shift);
keycode_lut[AKEYCODE_P] |= ((RETRO_DEVICE_ID_JOYPAD_R+1) << shift);
keycode_lut[AKEYCODE_R] |= ((RETRO_DEVICE_ID_JOYPAD_SELECT+1) << shift);
keycode_lut[AKEYCODE_Y] |= ((RETRO_DEVICE_ID_JOYPAD_START+1) << shift);
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);
keycode_lut[AKEYCODE_DPAD_RIGHT]|= ((RETRO_DEVICE_ID_JOYPAD_RIGHT+1) << shift);
break;
case ICADE_PROFILE_GAMESTOP_WIRELESS:
strlcpy(g_settings.input.device_names[port], "Gamestop Wireless",
sizeof(g_settings.input.device_names[port]));
@ -1447,6 +1455,21 @@ static void android_input_set_keybinds(void *data, unsigned device,
keycode_lut[AKEYCODE_BUTTON_L1]|= ((RETRO_DEVICE_ID_JOYPAD_L+1) << shift);
keycode_lut[AKEYCODE_BUTTON_R1]|= ((RETRO_DEVICE_ID_JOYPAD_R+1) << shift);
break;
case DEVICE_NVIDIA_SHIELD:
g_settings.input.device[port] = device;
strlcpy(g_settings.input.device_names[port], "NVIDIA Shield",
sizeof(g_settings.input.device_names[port]));
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_DUALANALOG;
keycode_lut[AKEYCODE_BUTTON_B] |= ((RETRO_DEVICE_ID_JOYPAD_A+1) << shift);
keycode_lut[AKEYCODE_BUTTON_A] |= ((RETRO_DEVICE_ID_JOYPAD_B+1) << shift);
keycode_lut[AKEYCODE_BUTTON_Y] |= ((RETRO_DEVICE_ID_JOYPAD_X+1) << shift);
keycode_lut[AKEYCODE_BUTTON_X] |= ((RETRO_DEVICE_ID_JOYPAD_Y+1) << shift);
keycode_lut[AKEYCODE_BUTTON_L1] |= ((RETRO_DEVICE_ID_JOYPAD_L+1) << shift);
keycode_lut[AKEYCODE_BUTTON_R1] |= ((RETRO_DEVICE_ID_JOYPAD_R+1) << shift);
keycode_lut[AKEYCODE_BUTTON_START] |= ((RARCH_MENU_TOGGLE+1) << shift);
keycode_lut[AKEYCODE_BUTTON_THUMBL] |= ((RETRO_DEVICE_ID_JOYPAD_SELECT+1) << shift);
keycode_lut[AKEYCODE_BUTTON_THUMBR] |= ((RETRO_DEVICE_ID_JOYPAD_START+1) << shift);
break;
case DEVICE_CCPCREATIONS_WIIUSE_IME:
g_settings.input.device[port] = device;
strlcpy(g_settings.input.device_names[port], "ccpCreations WiiUse IME",
@ -1570,8 +1593,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)
@ -1585,20 +1609,21 @@ static void android_input_poll(void *data)
// Read all pending events.
while (AInputQueue_hasEvents(android_app->inputQueue))
{
if (AInputQueue_getEvent(android_app->inputQueue, &event) >= 0)
int processed = 0;
while (AInputQueue_getEvent(android_app->inputQueue, &event) >= 0)
{
bool long_msg_enable = false;
int32_t handled = 1;
int action = 0;
char msg[128];
int source, id, keycode, type_event, state_id;
//int predispatched;
int predispatched;
msg[0] = 0;
//predispatched =AInputQueue_preDispatchEvent(android_app->inputQueue,event);
predispatched = AInputQueue_preDispatchEvent(android_app->inputQueue,event);
//if (predispatched)
//continue;
if (predispatched)
continue;
source = AInputEvent_getSource(event);
id = AInputEvent_getDeviceId(event);
@ -1621,9 +1646,25 @@ static void android_input_poll(void *data)
if (state_id < 0)
{
state_id = pads_connected;
state_device_ids[pads_connected++] = id;
if (g_settings.input.autodetect_enable)
{
bool primary = false;
input_autodetect_setup(android_app, msg, sizeof(msg), state_id, id, source, &primary);
if (primary)
{
RARCH_LOG("Found primary input device.\n");
memmove(state_device_ids + 1, state_device_ids, pads_connected * sizeof(state_device_ids[0]));
state_id = 0;
state_device_ids[0] = id;
pads_connected++;
}
else
state_device_ids[pads_connected++] = id;
}
else
state_device_ids[pads_connected++] = id;
input_autodetect_setup(android_app, msg, sizeof(msg), state_id, id, source);
long_msg_enable = true;
}
@ -1674,7 +1715,8 @@ static void android_input_poll(void *data)
if (source & ~(AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_MOUSE))
{
if (g_settings.input.dpad_emulation[state_id] != ANALOG_DPAD_NONE)
engine_handle_dpad(event, motion_pointer, state_id, msg, sizeof(msg), source, debug_enable);
engine_handle_dpad(event, motion_pointer, state_id, msg, sizeof(msg), source, debug_enable,
g_settings.input.dpad_emulation[state_id]);
}
else
{
@ -1712,9 +1754,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
@ -1724,28 +1763,40 @@ 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;
}
if (msg[0] != 0)
{
msg_queue_clear(g_extern.msg_queue);
msg_queue_push(g_extern.msg_queue, msg, 0, long_msg_enable ? 180 : 30);
RARCH_LOG("Input debug: %s\n", msg);
}
AInputQueue_finishEvent(android_app->inputQueue, event, handled);
processed = 1;
}
if (processed == 0)
RARCH_WARN("Failure reading next input event: %s\n", strerror(errno));
}
}
else if (ident == LOOPER_ID_MAIN)
@ -1759,8 +1810,22 @@ static int16_t android_input_state(void *data, const struct retro_keybind **bind
{
case RETRO_DEVICE_JOYPAD:
return ((state[port] & binds[port][id].joykey) && (port < pads_connected));
case RETRO_DEVICE_ANALOG:
if (port >= pads_connected)
return 0;
switch ((index << 1) | id)
{
case (RETRO_DEVICE_INDEX_ANALOG_LEFT << 1) | RETRO_DEVICE_ID_ANALOG_X:
return analog_state[port].lx;
case (RETRO_DEVICE_INDEX_ANALOG_LEFT << 1) | RETRO_DEVICE_ID_ANALOG_Y:
return analog_state[port].ly;
case (RETRO_DEVICE_INDEX_ANALOG_RIGHT << 1) | RETRO_DEVICE_ID_ANALOG_X:
return analog_state[port].rx;
case (RETRO_DEVICE_INDEX_ANALOG_RIGHT << 1) | RETRO_DEVICE_ID_ANALOG_Y:
return analog_state[port].ry;
}
case RETRO_DEVICE_POINTER:
switch(id)
switch (id)
{
case RETRO_DEVICE_ID_POINTER_X:
return pointer[index].x;
@ -1772,7 +1837,7 @@ static int16_t android_input_state(void *data, const struct retro_keybind **bind
return 0;
}
case RARCH_DEVICE_POINTER_SCREEN:
switch(id)
switch (id)
{
case RETRO_DEVICE_ID_POINTER_X:
return pointer[index].full_x;

View File

@ -67,7 +67,7 @@ end:
(*vm)->DetachCurrentThread(vm);
}
void input_autodetect_setup (void *data, char *msg, size_t sizeof_msg, unsigned port, unsigned id, int source)
void input_autodetect_setup(void *data, char *msg, size_t sizeof_msg, unsigned port, unsigned id, int source, bool *primary)
{
struct android_app *android_app = (struct android_app*)data;
@ -101,150 +101,153 @@ void input_autodetect_setup (void *data, char *msg, size_t sizeof_msg, unsigned
}
}
if (g_settings.input.autodetect_enable)
device = 0;
if (strstr(name_buf,"Logitech") && strstr(name_buf, "RumblePad 2"))
device = DEVICE_LOGITECH_RUMBLEPAD2;
else if (strstr(name_buf, "Logitech") && strstr(name_buf, "Dual Action"))
device = DEVICE_LOGITECH_DUAL_ACTION;
else if (strstr(name_buf, "Logitech") && strstr(name_buf, "Precision"))
device = DEVICE_LOGITECH_PRECISION_GAMEPAD;
else if (strstr(name_buf, "iControlPad-")) // followed by a 4 (hex) char HW id
device = DEVICE_ICONTROLPAD_HID_JOYSTICK;
else if (strstr(name_buf, "SEGA VIRTUA STICK High Grade"))
device = DEVICE_SEGA_VIRTUA_STICK_HIGH_GRADE;
else if (strstr(name_buf, "TTT THT Arcade console 2P USB Play"))
device = DEVICE_TTT_THT_ARCADE;
else if (strstr(name_buf, "TOMMO NEOGEOX Arcade Stick"))
device = DEVICE_TOMMO_NEOGEOX_ARCADE;
else if (strstr(name_buf, "Onlive Wireless Controller"))
device = DEVICE_ONLIVE_WIRELESS_CONTROLLER;
else if (strstr(name_buf, "MadCatz") && strstr(name_buf, "PC USB Wired Stick"))
device = DEVICE_MADCATZ_PC_USB_STICK;
else if (strstr(name_buf, "Logicool") && strstr(name_buf, "RumblePad 2"))
device = DEVICE_LOGICOOL_RUMBLEPAD2;
else if (strstr(name_buf, "Sun4i-keypad"))
device = DEVICE_IDROID_X360;
else if (strstr(name_buf, "Zeemote") && strstr(name_buf, "Steelseries free"))
device = DEVICE_ZEEMOTE_STEELSERIES;
else if (strstr(name_buf, "HuiJia USB GamePad"))
device = DEVICE_HUIJIA_USB_SNES;
else if (strstr(name_buf, "Smartjoy Family Super Smartjoy 2"))
device = DEVICE_SUPER_SMARTJOY;
else if (strstr(name_buf, "Jess Tech Dual Analog Rumble Pad"))
device = DEVICE_SAITEK_RUMBLE_P480;
else if (strstr(name_buf, "Microsoft"))
{
device = 0;
if (strstr(name_buf,"Logitech") && strstr(name_buf, "RumblePad 2"))
device = DEVICE_LOGITECH_RUMBLEPAD2;
else if (strstr(name_buf, "Logitech") && strstr(name_buf, "Dual Action"))
device = DEVICE_LOGITECH_DUAL_ACTION;
else if (strstr(name_buf, "Logitech") && strstr(name_buf, "Precision"))
device = DEVICE_LOGITECH_PRECISION_GAMEPAD;
else if (strstr(name_buf, "iControlPad-")) // followed by a 4 (hex) char HW id
device = DEVICE_ICONTROLPAD_HID_JOYSTICK;
else if (strstr(name_buf, "SEGA VIRTUA STICK High Grade"))
device = DEVICE_SEGA_VIRTUA_STICK_HIGH_GRADE;
else if (strstr(name_buf, "TTT THT Arcade console 2P USB Play"))
device = DEVICE_TTT_THT_ARCADE;
else if (strstr(name_buf, "TOMMO NEOGEOX Arcade Stick"))
device = DEVICE_TOMMO_NEOGEOX_ARCADE;
else if (strstr(name_buf, "Onlive Wireless Controller"))
device = DEVICE_ONLIVE_WIRELESS_CONTROLLER;
else if (strstr(name_buf, "MadCatz") && strstr(name_buf, "PC USB Wired Stick"))
device = DEVICE_MADCATZ_PC_USB_STICK;
else if (strstr(name_buf, "Logicool") && strstr(name_buf, "RumblePad 2"))
device = DEVICE_LOGICOOL_RUMBLEPAD2;
else if (strstr(name_buf, "Sun4i-keypad"))
device = DEVICE_IDROID_X360;
else if (strstr(name_buf, "Zeemote") && strstr(name_buf, "Steelseries free"))
device = DEVICE_ZEEMOTE_STEELSERIES;
else if (strstr(name_buf, "HuiJia USB GamePad"))
device = DEVICE_HUIJIA_USB_SNES;
else if (strstr(name_buf, "Smartjoy Family Super Smartjoy 2"))
device = DEVICE_SUPER_SMARTJOY;
else if (strstr(name_buf, "Jess Tech Dual Analog Rumble Pad"))
device = DEVICE_SAITEK_RUMBLE_P480;
else if (strstr(name_buf, "Microsoft"))
{
if (strstr(name_buf, "Dual Strike"))
device = DEVICE_MS_SIDEWINDER_DUAL_STRIKE;
else if (strstr(name_buf, "SideWinder"))
device = DEVICE_MS_SIDEWINDER;
else if (strstr(name_buf, "X-Box 360") || strstr(name_buf, "X-Box")
|| strstr(name_buf, "Xbox 360 Wireless Receiver"))
device = DEVICE_MS_XBOX;
}
else if (strstr(name_buf, "WiseGroup"))
{
if (strstr(name_buf, "TigerGame") || strstr(name_buf, "Game Controller Adapter")
|| strstr(name_buf, "JC-PS102U") || strstr(name_buf, "Dual USB Joypad"))
{
if (strstr(name_buf, "WiseGroup"))
device = DEVICE_WISEGROUP_PLAYSTATION2;
else if (strstr(name_buf, "JC-PS102U"))
device = DEVICE_JCPS102_PLAYSTATION2;
else
device = DEVICE_GENERIC_PLAYSTATION2_CONVERTER;
}
}
else if (strstr(name_buf, "PLAYSTATION(R)3") || strstr(name_buf, "Dualshock3")
|| strstr(name_buf,"Sixaxis") || strstr(name_buf, "Gasia,Co") ||
(strstr(name_buf, "Gamepad 0") || strstr(name_buf, "Gamepad 1") ||
strstr(name_buf, "Gamepad 2") || strstr(name_buf, "Gamepad 3")))
{
if (strstr(name_buf, "Gamepad 0") || strstr(name_buf, "Gamepad 1") ||
strstr(name_buf, "Gamepad 2") || strstr(name_buf, "Gamepad 3"))
device = DEVICE_PLAYSTATION3_VERSION1;
else
device = DEVICE_PLAYSTATION3_VERSION2;
}
else if (strstr(name_buf, "MOGA"))
device = DEVICE_MOGA;
else if (strstr(name_buf, "Sony Navigation Controller"))
device = DEVICE_PSMOVE_NAVI;
else if (strstr(name_buf, "OUYA Game Controller"))
device = DEVICE_OUYA;
else if (strstr(name_buf, "adc joystick"))
device = DEVICE_JXD_S7300B;
else if (strstr(name_buf, "idroid:con"))
device = DEVICE_IDROID_CON;
else if (strstr(name_buf, "NYKO PLAYPAD PRO"))
device = DEVICE_NYKO_PLAYPAD_PRO;
else if (strstr(name_buf, "2-Axis, 8-Button"))
device = DEVICE_GENIUS_MAXFIRE_G08XU;
else if (strstr(name_buf, "USB,2-axis 8-button gamepad"))
device = DEVICE_USB_2_AXIS_8_BUTTON_GAMEPAD;
else if (strstr(name_buf, "BUFFALO BGC-FC801"))
device = DEVICE_BUFFALO_BGC_FC801;
else if (strstr(name_buf, "RetroUSB.com RetroPad"))
device = DEVICE_RETROUSB_RETROPAD;
else if (strstr(name_buf, "RetroUSB.com SNES RetroPort"))
device = DEVICE_RETROUSB_SNES_RETROPORT;
else if (strstr(name_buf, "CYPRESS USB"))
device = DEVICE_CYPRESS_USB;
else if (strstr(name_buf, "Mayflash Wii Classic"))
device = DEVICE_MAYFLASH_WII_CLASSIC;
else if (strstr(name_buf, "SZMy-power LTD CO. Dual Box WII"))
device = DEVICE_SZMY_POWER_DUAL_BOX_WII;
else if (strstr(name_buf, "Toodles 2008 ChImp"))
device = DEVICE_TOODLES_2008_CHIMP;
else if (strstr(name_buf, "joy_key"))
device = DEVICE_ARCHOS_GAMEPAD;
else if (strstr(name_buf, "matrix_keyboard"))
device = DEVICE_JXD_S5110;
else if (strstr(name_buf, "keypad-zeus") || (strstr(name_buf, "keypad-game-zeus")))
device = DEVICE_XPERIA_PLAY;
else if (strstr(name_buf, "Broadcom Bluetooth HID"))
device = DEVICE_BROADCOM_BLUETOOTH_HID;
else if (strstr(name_buf, "USB Gamepad"))
device = DEVICE_THRUST_PREDATOR;
else if (strstr(name_buf, "DragonRise"))
device = DEVICE_DRAGONRISE;
else if (strstr(name_buf, "Thrustmaster T Mini"))
device = DEVICE_THRUSTMASTER_T_MINI;
else if (strstr(name_buf, "2Axes 11Keys Game Pad"))
device = DEVICE_TOMEE_NES_USB;
else if (strstr(name_buf, "rk29-keypad") || strstr(name_buf, "GAMEMID"))
device = DEVICE_GAMEMID;
else if (strstr(name_buf, "USB Gamepad"))
device = DEVICE_DEFENDER_GAME_RACER_CLASSIC;
else if (strstr(name_buf, "HOLTEK JC - U912F vibration game"))
device = DEVICE_HOLTEK_JC_U912F;
if (strstr(current_ime, "net.obsidianx.android.mogaime"))
{
device = DEVICE_MOGA_IME;
snprintf(name_buf, sizeof(name_buf), "MOGA IME");
}
else if (strstr(current_ime, "com.ccpcreations.android.WiiUseAndroid"))
{
device = DEVICE_CCPCREATIONS_WIIUSE_IME;
snprintf(name_buf, sizeof(name_buf), "ccpcreations WiiUse");
}
else if (strstr(current_ime, "com.hexad.bluezime"))
{
device = DEVICE_ICONTROLPAD_BLUEZ_IME;
snprintf(name_buf, sizeof(name_buf), "iControlpad SPP mode (using Bluez IME)");
}
if (source == AINPUT_SOURCE_KEYBOARD && device != DEVICE_XPERIA_PLAY)
device = DEVICE_KEYBOARD_RETROPAD;
if (driver.input->set_keybinds)
driver.input->set_keybinds(driver.input_data, device, port, id,
(1ULL << KEYBINDS_ACTION_SET_DEFAULT_BINDS));
if (strstr(name_buf, "Dual Strike"))
device = DEVICE_MS_SIDEWINDER_DUAL_STRIKE;
else if (strstr(name_buf, "SideWinder"))
device = DEVICE_MS_SIDEWINDER;
else if (strstr(name_buf, "X-Box 360") || strstr(name_buf, "X-Box")
|| strstr(name_buf, "Xbox 360 Wireless Receiver"))
device = DEVICE_MS_XBOX;
}
else if (strstr(name_buf, "WiseGroup"))
{
if (strstr(name_buf, "TigerGame") || strstr(name_buf, "Game Controller Adapter")
|| strstr(name_buf, "JC-PS102U") || strstr(name_buf, "Dual USB Joypad"))
{
if (strstr(name_buf, "WiseGroup"))
device = DEVICE_WISEGROUP_PLAYSTATION2;
else if (strstr(name_buf, "JC-PS102U"))
device = DEVICE_JCPS102_PLAYSTATION2;
else
device = DEVICE_GENERIC_PLAYSTATION2_CONVERTER;
}
}
else if (strstr(name_buf, "PLAYSTATION(R)3") || strstr(name_buf, "Dualshock3")
|| strstr(name_buf,"Sixaxis") || strstr(name_buf, "Gasia,Co") ||
(strstr(name_buf, "Gamepad 0") || strstr(name_buf, "Gamepad 1") ||
strstr(name_buf, "Gamepad 2") || strstr(name_buf, "Gamepad 3")))
{
if (strstr(name_buf, "Gamepad 0") || strstr(name_buf, "Gamepad 1") ||
strstr(name_buf, "Gamepad 2") || strstr(name_buf, "Gamepad 3"))
device = DEVICE_PLAYSTATION3_VERSION1;
else
device = DEVICE_PLAYSTATION3_VERSION2;
}
else if (strstr(name_buf, "MOGA"))
device = DEVICE_MOGA;
else if (strstr(name_buf, "Sony Navigation Controller"))
device = DEVICE_PSMOVE_NAVI;
else if (strstr(name_buf, "OUYA Game Controller"))
device = DEVICE_OUYA;
else if (strstr(name_buf, "adc joystick"))
device = DEVICE_JXD_S7300B;
else if (strstr(name_buf, "idroid:con"))
device = DEVICE_IDROID_CON;
else if (strstr(name_buf, "NYKO PLAYPAD PRO"))
device = DEVICE_NYKO_PLAYPAD_PRO;
else if (strstr(name_buf, "2-Axis, 8-Button"))
device = DEVICE_GENIUS_MAXFIRE_G08XU;
else if (strstr(name_buf, "USB,2-axis 8-button gamepad"))
device = DEVICE_USB_2_AXIS_8_BUTTON_GAMEPAD;
else if (strstr(name_buf, "BUFFALO BGC-FC801"))
device = DEVICE_BUFFALO_BGC_FC801;
else if (strstr(name_buf, "RetroUSB.com RetroPad"))
device = DEVICE_RETROUSB_RETROPAD;
else if (strstr(name_buf, "RetroUSB.com SNES RetroPort"))
device = DEVICE_RETROUSB_SNES_RETROPORT;
else if (strstr(name_buf, "CYPRESS USB"))
device = DEVICE_CYPRESS_USB;
else if (strstr(name_buf, "Mayflash Wii Classic"))
device = DEVICE_MAYFLASH_WII_CLASSIC;
else if (strstr(name_buf, "SZMy-power LTD CO. Dual Box WII"))
device = DEVICE_SZMY_POWER_DUAL_BOX_WII;
else if (strstr(name_buf, "Toodles 2008 ChImp"))
device = DEVICE_TOODLES_2008_CHIMP;
else if (strstr(name_buf, "joy_key"))
device = DEVICE_ARCHOS_GAMEPAD;
else if (strstr(name_buf, "matrix_keyboard"))
device = DEVICE_JXD_S5110;
else if (strstr(name_buf, "keypad-zeus") || (strstr(name_buf, "keypad-game-zeus")))
device = DEVICE_XPERIA_PLAY;
else if (strstr(name_buf, "Broadcom Bluetooth HID"))
device = DEVICE_BROADCOM_BLUETOOTH_HID;
else if (strstr(name_buf, "USB Gamepad"))
device = DEVICE_THRUST_PREDATOR;
else if (strstr(name_buf, "DragonRise"))
device = DEVICE_DRAGONRISE;
else if (strstr(name_buf, "Thrustmaster T Mini"))
device = DEVICE_THRUSTMASTER_T_MINI;
else if (strstr(name_buf, "2Axes 11Keys Game Pad"))
device = DEVICE_TOMEE_NES_USB;
else if (strstr(name_buf, "rk29-keypad") || strstr(name_buf, "GAMEMID"))
device = DEVICE_GAMEMID;
else if (strstr(name_buf, "USB Gamepad"))
device = DEVICE_DEFENDER_GAME_RACER_CLASSIC;
else if (strstr(name_buf, "HOLTEK JC - U912F vibration game"))
device = DEVICE_HOLTEK_JC_U912F;
else if (strstr(name_buf, "NVIDIA Controller"))
{
device = DEVICE_NVIDIA_SHIELD;
port = 0; // Shield is always player 1.
*primary = true;
}
if (strstr(current_ime, "net.obsidianx.android.mogaime"))
{
device = DEVICE_MOGA_IME;
snprintf(name_buf, sizeof(name_buf), "MOGA IME");
}
else if (strstr(current_ime, "com.ccpcreations.android.WiiUseAndroid"))
{
device = DEVICE_CCPCREATIONS_WIIUSE_IME;
snprintf(name_buf, sizeof(name_buf), "ccpcreations WiiUse");
}
else if (strstr(current_ime, "com.hexad.bluezime"))
{
device = DEVICE_ICONTROLPAD_BLUEZ_IME;
snprintf(name_buf, sizeof(name_buf), "iControlpad SPP mode (using Bluez IME)");
}
if (source == AINPUT_SOURCE_KEYBOARD && device != DEVICE_XPERIA_PLAY)
device = DEVICE_KEYBOARD_RETROPAD;
if (driver.input->set_keybinds)
driver.input->set_keybinds(driver.input_data, device, port, id,
(1ULL << KEYBINDS_ACTION_SET_DEFAULT_BINDS));
if (name_buf[0] != 0)
snprintf(msg, sizeof_msg, "Port %d: %s.\n", port, name_buf);

View File

@ -24,6 +24,7 @@
enum {
ICADE_PROFILE_RED_SAMURAI = 0,
ICADE_PROFILE_IPEGA_PG9017,
ICADE_PROFILE_IPEGA_PG9017_MODE2,
ICADE_PROFILE_GAMESTOP_WIRELESS,
} icade_profile_enums;
@ -60,6 +61,7 @@ enum {
AKEYCODE_NUMPAD_7 = 151,
AKEYCODE_NUMPAD_8 = 152,
AKEYCODE_NUMPAD_9 = 153,
AKEYCODE_WINDOW = 171,
AKEYCODE_BUTTON_1 = 188,
AKEYCODE_BUTTON_2 = 189,
AKEYCODE_BUTTON_3 = 190,
@ -81,7 +83,7 @@ enum {
#define LAST_KEYCODE AKEYCODE_ASSIST
void input_autodetect_setup (void *data, char *msg, size_t sizeof_msg, unsigned port, unsigned id, int source);
void input_autodetect_setup(void *data, char *msg, size_t sizeof_msg, unsigned port, unsigned id, int source, bool *primary);
/* Xperia Play externs */
extern unsigned zeus_port;

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

View File

@ -1,7 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.retroarch"
android:versionCode="17"
android:versionName="0.9.9.3" >
android:versionCode="23"
android:versionName="0.9.9.6" >
<uses-feature android:glEsVersion="0x00020000" />
<uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
<uses-sdk
@ -13,29 +13,36 @@
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity android:name="org.retroarch.browser.RetroArch">
android:label="@string/app_name"
android:hasCode="true">
<activity android:name=".browser.CoreSelection"></activity>
<activity android:name=".browser.HistorySelection"></activity>
<activity android:name=".browser.DisplayRefreshRateTest"></activity>
<activity android:name=".browser.RefreshRateSetOS"></activity>
<activity android:name=".browser.MainMenuActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</activity>
<activity android:name=".browser.HoneycombPopupMenu"></activity>
<activity android:name=".browser.LazyPopupMenu"></activity>
<activity android:name=".browser.PopupMenuAbstract"></activity>
<activity android:name=".browser.ReportIME"></activity>
<activity android:name=".browser.HelpActivity"></activity>
<activity android:name=".browser.FileWrapper"></activity>
<activity android:name=".browser.DirectoryActivity"></activity>
<activity android:name=".browser.ROMActivity"></activity>
<activity android:name=".browser.RetroTVMode"></activity>
<activity android:name="org.retroarch.browser.DisplayRefreshRateTest"></activity>
<activity android:name="org.retroarch.browser.RefreshRateSetOS"></activity>
<activity android:name="org.retroarch.browser.SettingsActivity"></activity>
<activity android:name="org.retroarch.browser.HelpActivity"></activity>
<activity android:name="org.retroarch.browser.DirectoryActivity"></activity>
<activity android:name="org.retroarch.browser.ROMActivity"></activity>
<activity android:name=".browser.ShaderActivity"></activity>
<activity android:name=".browser.OverlayActivity"></activity>
<activity android:name=".browser.ROMDirActivity"></activity>
<activity android:name=".browser.SRMDirActivity"></activity>
<activity android:name=".browser.StateDirActivity"></activity>
<activity android:name=".browser.SystemDirActivity"></activity>
<activity android:name="org.retroarch.browser.ShaderActivity"></activity>
<activity android:name="org.retroarch.browser.OverlayActivity"></activity>
<activity android:name="org.retroarch.browser.ROMDirActivity"></activity>
<activity android:name="org.retroarch.browser.SRMDirActivity"></activity>
<activity android:name="org.retroarch.browser.StateDirActivity"></activity>
<activity android:name="org.retroarch.browser.SystemDirActivity"></activity>
<activity android:name="org.retroarch.browser.RetroActivity" android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale">
<activity android:name=".browser.RetroActivity" android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale" android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
<meta-data android:name="android.app.lib_name" android:value="retroarch-activity" />
<meta-data android:name="android.app.func_name" android:value="ANativeActivity_onCreate" />
</activity>

View File

@ -1,21 +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_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_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_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"

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical" >
<TextView
android:id="@+id/assets_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/extracting_assets_please_wait_" />
<ProgressBar
android:id="@+id/assets_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</LinearLayout>

View File

@ -9,5 +9,5 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="40px"
android:text="There can be two reasons for this:\n\na) Either your device is not powerful enough to run the core you've selected at fullspeed.\n\nb) The refresh rate of the screen that your device reports is wrong. More on b) below.\n\n== REFRESH RATES AND RETROARCH ==\n\nUnlike other emulators, RetroArch does not use frameskipping. To get smooth gameplay and sound that are remotely close to the original hardware, RetroArch Android uses static synchronization. If you notice any skipping music or 'jerkiness' - rest assured it's not our code - it's likely that your device reports a wrong refreshrate to the OS (Android in this case). For instance, certain devices like the Note 2 have refresh rates below 60Hz.\n\nTo get any decent audio and video out of any application, you will have to synchronize the game's refresh rate with that of your screen - if the refresh rate cannot be properly synchronized, you will get bad audio pops and video glitchiness.\n\nThe problem is that a good many Android devices 'report' the wrong refresh rate to Android. The Samsung Galaxy S3 is known for doing this - it reports a 60Hz refresh rate when it isn't (the Note 2 for instance has a 58Hz screen but at least reports it correctly). So, because it 'reports' a wrong refresh rate, RetroArch will not yield good results.\n\nIf you experience any audio pops on cores that should be running fullspeed on your device, you should go with manual synchronization. To do this, you can start by calcuating your screens refresh rate with the 'Calibrate refresh rate' setting. This option can give a good guess, but for best results you should edit the value it returns in the 'Forced refresh rate (Hz)' option and set it manually - start at the value it returns and if it still audio pops/crackles, raise or lower the value (0.01 intervals is a good place to start) until you hit a sweet spot.\n\nIf you think your device reports the correct value, you can use that instead by selecting the 'Set OS-reported refresh rate' option instead.\n\nWith a bit of experimentation you can get this right easily - I am running games on a single-core Cortex A8 device (1.2GHz - Allwinner A10) and I get no sound pops or any video glitchiness at all in most cores. So this is entirely a refresh rate issue that you can overcome easily on most devices by doing what I state above." />
android:text="There can be a couple of reasons for this:\n\na) Either your device is not powerful enough to run the core you've selected at fullspeed.\n\nb) The refresh rate of the screen that your device reports is wrong. More on b) below.\n\nc) Just turn on 'Threaded video' to save yourself all the trouble of trying to get static syncing to work right on your device.\n\n== REFRESH RATES AND RETROARCH ==\n\nUnlike other emulators, RetroArch does not use frameskipping. To get smooth gameplay and sound that are remotely close to the original hardware, RetroArch Android uses static synchronization. If you notice any skipping music or 'jerkiness' - rest assured it's not our code - it's likely that your device reports a wrong refreshrate to the OS (Android in this case). For instance, certain devices like the Note 2 have refresh rates below 60Hz.\n\nTo get any decent audio and video out of any application, you will have to synchronize the game's refresh rate with that of your screen - if the refresh rate cannot be properly synchronized, you will get bad audio pops and video glitchiness.\n\nThe problem is that a good many Android devices 'report' the wrong refresh rate to Android. The Samsung Galaxy S3 is known for doing this - it reports a 60Hz refresh rate when it isn't (the Note 2 for instance has a 58Hz screen but at least reports it correctly). So, because it 'reports' a wrong refresh rate, RetroArch will not yield good results.\n\nIf you experience any audio pops on cores that should be running fullspeed on your device, you should go with manual synchronization. To do this, you can start by calcuating your screens refresh rate with the 'Calibrate refresh rate' setting. This option can give a good guess, but for best results you should edit the value it returns in the 'Forced refresh rate (Hz)' option and set it manually - start at the value it returns and if it still audio pops/crackles, raise or lower the value (0.01 intervals is a good place to start) until you hit a sweet spot.\n\nIf you think your device reports the correct value, you can use that instead by selecting the 'Set OS-reported refresh rate' option instead.\n\nWith a bit of experimentation you can get this right easily - I am running games on a single-core Cortex A8 device (1.2GHz - Allwinner A10) and I get no sound pops or any video glitchiness at all in most cores. So this is entirely a refresh rate issue that you can overcome easily on most devices by doing what I state above." />
</LinearLayout>

View File

@ -9,5 +9,5 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="40px"
android:text="The following pads have been added to the autodetection list:\n\n* Logitech/Logicool Rumblepad 2\n* Microsoft Sidewinder USB (ISSUE - diagonals not working).\n* Microsoft Xbox 360 Wired/Wireless (ISSUE - diagonals not working).\n* PS3 Sixaxis/DualShock 3 (using either USB or Dancingpixelstudios' IME app)\n* MOGA (using either 'root' gamepad mode or official IME app)\n* JXD S5110\n* Snakebyte idroid\n* Logitech Dual Action\n* Mayflash Super Joy Box 3 Pro\n* RetroUSB SNES RetroPort\n* RetroUSB NES RetroPad\n* Buffalo SNES Pad\n* Elecom PS1/PS2 to USB\n* Archos gamepad\n* Xbox 1 (Titanium X-Joy Converter) (ISSUE - diagonals not working).\n* Red Samurai (IME app Bluetooth or gamepad mode)\n* Xperia Play\n* Trust Raptor\n* Logitech F710\n* DragonRise USB\n* Madcatz PS3 fighting stick\n* iControlPad (HID joystick profile or SPP profile in tandem with Bluez IME)\n* iPega (gamepad mode, select it in iCade profile)\n* PC2JAMMA-USB (TODO - TEST)\n* Genius MaxFire G-08XU\n* Zeemote Steelseries\n* Saitek Rumblepad\n* Super Smart Joy\n* Groupwise PS2 to USB converter\n* Toodles 2008 Chimp\n* Sega Saturn USB pad\n* Mayflash Wii Classic\n* Mayflash PS2 to USB\n* Nintendo Wii (using ccpcreations.WiiUse IME app)\n* Nyko Playpad Pro" />
android:text="The following pads have been added to the autodetection list:\n\n* Logitech/Logicool Rumblepad 2\n* Microsoft Sidewinder USB (ISSUE - diagonals not working).\n* Microsoft Xbox 360 Wired/Wireless.\n* PS3 Sixaxis/DualShock 3 (using either USB or Dancingpixelstudios' IME app)\n* MOGA (using either 'root' gamepad mode or official IME app)\n* JXD S5110\n* Snakebyte idroid\n* Logitech Dual Action\n* Mayflash Super Joy Box 3 Pro\n* RetroUSB SNES RetroPort\n* RetroUSB NES RetroPad\n* Buffalo SNES Pad\n* Elecom PS1/PS2 to USB\n* Archos gamepad\n* Xbox 1 (Titanium X-Joy Converter) (ISSUE - diagonals not working).\n* Red Samurai (IME app Bluetooth or gamepad mode)\n* Xperia Play\n* Trust Raptor\n* Logitech F710\n* DragonRise USB\n* Madcatz PS3 fighting stick\n* iControlPad (HID joystick profile or SPP profile in tandem with Bluez IME)\n* iPega (gamepad mode, select it in iCade profile)\n* PC2JAMMA-USB (TODO - TEST)\n* Genius MaxFire G-08XU\n* Zeemote Steelseries\n* Saitek Rumblepad\n* Super Smart Joy\n* Groupwise PS2 to USB converter\n* Toodles 2008 Chimp\n* Sega Saturn USB pad\n* Mayflash Wii Classic\n* Mayflash PS2 to USB\n* Nintendo Wii (using ccpcreations.WiiUse IME app)\n* Nyko Playpad Pro\n*Nvidia Shield" />
</LinearLayout>

View File

@ -25,5 +25,6 @@
* Mednafen Virtual Boy [Virtual Boy] : Dual-core ARM Cortex A9 CPU or higher.\n
* Mednafen PC Engine [PC Engine] : Has been tested to run at fullspeed on an ARM Cortex A8 single-core CPU.\n
* TyrQuake [Quake 1] : Has been tested to run around give or take 55-60fps at 320x240 resolution on an ARM Cortex A8 single-core CPU.\n
* Picodrive : Has been tested to run at fullspeed with Knuckles Chaotix [a 32X game] on an ARM Cortex A8 single-core CPU.\n
" />
</LinearLayout>

View File

@ -10,6 +10,73 @@
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
- NVidia Shield\n
- iControlPad changes\n
- Logitech Rumblepad 2 (added RETRO_DEVICE_ID_ANALOG support)\n
- Xbox 360 (D-pad should be fixed, added RETRO_DEVICE_ID_ANALOG support, triggers should work)\n
* [RGUI] Throttle with timers - no more irrational super-fast menu with threaded video.\n
* [Android] Appeal to low-latency audio Android devices for OpenSL (Android 4.1 and up)\n
* [Android] Look for the optimal sampling rate instead of assuming 48KHz as default - should fix Nexus 10\n
* [Android] Added 'Optimal Device Settings' and added support for both Nexus 7 2013 and Nvidia Shield\n
* [Android] Added adaptive jittering for threaded video option. Should now be much more tolerable.\n
* [Android] Enable threaded video by default - leave static syncing for expert users.\n
* (LIBRETRO) Added Picodrive (PC/Android/iOS/Blackberry)\n
* (LIBRETRO) Added SNES9x mainline.\n
* (LIBRETRO) Added Stella.\n
* (LIBRETRO) Added Desmume.\n
* [TyrQuake] Added dual analog core option.\n
* [NEStopia] Add Core Options for blargg NTSC.\n
* [FBA core] Prevent diagnostics at startup from being enabled to avoid crash.\n
* [Stella] 2 players should work now.\n
* [Genesis Plus GX] Updated to latest version.\n
* [VBA Next] Start sanitizing some code back to VBA-M proper.\n
* [NX Engine/Cave Story] Fixed big-endian bug on scrolling backgrounds.\n
r17 (June 28, 2013)\n\n
* [Android] Input autodetection expanded -\n
- Xperia Play controls fixed once and for all (thanks to littleguy77)\n

View File

@ -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">
<ImageView
android:id="@+id/icon"
@ -11,13 +11,27 @@
android:layout_height="48dp"
android:contentDescription="@string/file_type_icon"
android:padding="8dp" />
<TextView
android:id="@+id/name"
android:layout_width="0dp"
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="0.5"
android:textSize="18sp" />
android:layout_gravity="center_vertical"
android:orientation="vertical" >
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:textSize="18sp" />
<TextView
android:id="@+id/sub_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:visibility="gone"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>

View File

@ -1,11 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@+id/rarch_settings" android:title="@string/rarch_settings" android:showAsAction="ifRoom" />
<item android:id="@+id/help" android:title="@string/help"></item>
<item android:id="@+id/input_method_select" android:title="@string/input_method" android:showAsAction="ifRoom" />
<item android:id="@+id/report_ime" android:title="@string/report_ime"></item>
<item android:id="@+id/report_refreshrate" android:title="@string/report_refreshrate"></item>
<item android:id="@+id/retroarch_guide" android:title="@string/retroarch_guide"></item>
<item android:id="@+id/cores_guide" android:title="@string/cores_guide"></item>
<item android:id="@+id/overlay_guide" android:title="@string/overlay_guide"></item>
</menu>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@+id/settings"
android:title="@string/settings"
android:title="Options"
android:icon="@drawable/ic_file"
android:showAsAction="ifRoom" />
</menu>

View File

@ -33,6 +33,7 @@
<string-array name="icade_profiles">
<item>Red Samurai</item>
<item>iPega PG-9017</item>
<item>iPega PG-9017 (Mode 2)</item>
<item>Gamestop Wireless</item>
</string-array>
@ -40,6 +41,7 @@
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
</string-array>
<string-array name="key_bind_values">

View File

@ -3,20 +3,12 @@
<string name="app_name">RetroArch</string>
<string name="input_method">Input Method</string>
<string name="file_type_icon">File type icon</string>
<string name="video_settings">Video Settings</string>
<string name="rarch_settings">Settings</string>
<string name="audio_settings">Audio Settings</string>
<string name="input_settings">Input Settings</string>
<string name="general_settings">General Settings</string>
<string name="settings">Settings</string>
<string name="retroarch_guide">RetroArch Guide</string>
<string name="cores_guide">Cores Guide</string>
<string name="overlay_guide">Overlay How-to Guide</string>
<string name="key_bind_title">Select the button to use</string>
<string name="key_bind_clear">Unbind</string>
<string name="help">Help</string>
<string name="report_ime">Report IME</string>
<string name="report_refreshrate">Report Refresh Rate</string>
<string name="key_bind_detect">Detect</string>
<string name="optimal_settings_device">Optimal device settings</string>
<string name="extracting_assets_please_wait_">Extracting assets, please wait ...</string>
</resources>

View File

@ -1,79 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:title="RetroArch Settings" >
android:title="RetroArch - Main Menu" >
<PreferenceScreen android:title="Path Settings">
<PreferenceCategory android:title="ROM paths">
<Preference android:title="ROM directory"
android:summary="Sets directory where ROM browser will first browse for ROM files.">
<intent
android:targetClass="org.retroarch.browser.ROMDirActivity"
android:targetPackage="org.retroarch" />
</Preference>
</PreferenceCategory>
<PreferenceCategory android:title="Save files">
<CheckBoxPreference android:title="Enable custom directory"
android:summary="Enables use of custom save file folder. (.srm) save files will be saved and loaded to configured directory. If not enabled, save files will reside in ROM folder."
android:key="savefile_directory_enable"
android:defaultValue="false"/>
<Preference android:title="Savefile directory"
android:summary="Sets directory where to save and load game save files."
android:dependency="savefile_directory_enable">
<intent
android:targetClass="org.retroarch.browser.SRMDirActivity"
android:targetPackage="org.retroarch" />
</Preference>
</PreferenceCategory>
<PreferenceCategory android:title="Save states">
<CheckBoxPreference android:title="Enable custom directory"
android:summary="Enables use of custom save state folder. (.state) save states will be saved and loaded to configured directory. If not enabled, save states will reside in ROM folder."
android:key="savestate_directory_enable"
android:defaultValue="false"/>
<Preference android:title="Save state directory"
android:summary="Sets directory where to save and load game save states."
android:dependency="savestate_directory_enable">
<intent
android:targetClass="org.retroarch.browser.StateDirActivity"
android:targetPackage="org.retroarch" />
</Preference>
</PreferenceCategory>
<PreferenceCategory android:title="System">
<CheckBoxPreference android:title="Enable custom directory"
android:summary="Enables use of custom system folder. Cores will look for system specific files, like BIOSes, in this folder. If not enabled, it will look in the ROM folder."
android:key="system_directory_enable"
android:defaultValue="false"/>
<Preference android:title="System directory"
android:summary="Sets directory where system files are loaded from."
android:dependency="system_directory_enable">
<intent
android:targetClass="org.retroarch.browser.SystemDirActivity"
android:targetPackage="org.retroarch" />
</Preference>
</PreferenceCategory>
<PreferenceScreen android:title="TV Mode">
<intent
android:targetClass="org.retroarch.browser.RetroTVMode"
android:targetPackage="org.retroarch" />
</PreferenceScreen>
<PreferenceScreen android:title="System Settings" >
<PreferenceCategory android:title="General" >
<CheckBoxPreference
android:defaultValue="true"
android:key="savestate_auto_load"
android:summary="Loads an automatically created savestate (*.state.auto) at startup."
android:title="Auto load state" />
<CheckBoxPreference
android:defaultValue="false"
android:key="savestate_auto_save"
android:summary="Automatically saves state (*.state.auto) when exiting game."
android:title="Auto save state" />
</PreferenceCategory>
<PreferenceCategory android:title="Rewinding" >
<CheckBoxPreference
android:defaultValue="false"
android:key="rewind_enable"
android:summary="Enable real-time rewinding of gameplay. (WARNING: Very CPU intensive - will decrease ingame performance by a lot - only use this option on a powerful device)."
android:title="Enable" />
</PreferenceCategory>
<PreferenceScreen android:title="Load Core">
<intent
android:targetClass="org.retroarch.browser.CoreSelection"
android:targetPackage="org.retroarch" />
</PreferenceScreen>
<PreferenceScreen android:title="Video Settings" >
<PreferenceScreen android:title="Load Game">
<intent
android:targetClass="org.retroarch.browser.ROMActivity"
android:targetPackage="org.retroarch" />
</PreferenceScreen>
<PreferenceScreen android:title="Load Game (History)">
<intent
android:targetClass="org.retroarch.browser.HistorySelection"
android:targetPackage="org.retroarch" />
</PreferenceScreen>
<PreferenceScreen android:title="Video Options" >
<PreferenceCategory android:title="General" >
<CheckBoxPreference
android:defaultValue="true"
@ -100,7 +49,7 @@
</PreferenceCategory>
<PreferenceCategory android:title="Synchronization" >
<CheckBoxPreference
android:defaultValue="false"
android:defaultValue="true"
android:key="video_threaded"
android:summary="Uses a multi-threaded video driver. Is likely to improve performance at the expense of slightly more latency and jitter. Use this if you have troubles getting good video and audio."
android:title="Threaded video driver" />
@ -124,21 +73,21 @@
android:targetPackage="org.retroarch" />
</Preference>
</PreferenceCategory>
<PreferenceCategory android:title="Shaders (1st pass)" >
<PreferenceCategory android:title="Shaders" >
<CheckBoxPreference
android:defaultValue="true"
android:key="video_smooth"
android:summary="Applies Bilinear filtering, smooths out edges (settings still apply even if no shader is selected)."
android:title="Bilinear filter" />
<CheckBoxPreference
android:summary="Enable first pass shader (WARNING: recommended system requirements for these shaders is a Tegra 4/Exynos5 class GPU and/or higher)."
android:summary="Enable first pass shader (WARNING: recommended system requirements for these shaders is a Tegra 4 / Exynos 5 class GPU and/or higher)."
android:defaultValue="false"
android:key="video_shader_enable"
android:title="Enable" />
<Preference
android:summary="Sets GLES2 style XML shader."
android:title="XML shader"
android:summary="Sets GLES2 style shader."
android:title="GLSL shader"
android:dependency="video_shader_enable" >
<intent
android:targetClass="org.retroarch.browser.ShaderActivity"
@ -152,7 +101,7 @@
android:defaultValue="true"/>
</PreferenceCategory>
</PreferenceScreen>
<PreferenceScreen android:title="Audio Settings" >
<PreferenceScreen android:title="Audio Options" >
<PreferenceCategory android:title="Audio" >
<CheckBoxPreference
android:defaultValue="true"
@ -164,10 +113,20 @@
android:summary="Enable dynamic rate control (recommended)."
android:title="Dynamic Rate Control"
android:dependency="audio_enable" />
<CheckBoxPreference
android:defaultValue="false"
android:key="audio_high_latency"
android:summary="Use (very) high latency audio. Necessary for older Android devices with poor audio drivers."
android:title="High latency audio"
android:dependency="audio_enable" />
</PreferenceCategory>
</PreferenceScreen>
<PreferenceScreen android:title="Input Settings" >
<PreferenceScreen android:title="Input Options" >
<PreferenceCategory android:title="General" >
<CheckBoxPreference android:title="Enable global configuration"
android:summary="Enable global settings for all cores. Leave disabled if you want per-core settings."
android:key="global_config_enable"
android:defaultValue="true"/>
<ListPreference
android:entries="@array/back_options"
android:entryValues="@array/back_options_values"
@ -449,5 +408,121 @@
android:title="R3 Button" />
</PreferenceScreen>
</PreferenceCategory>
<PreferenceCategory android:title="Diagnostics" >
<Preference android:title="Report IME"
android:summary="Reports the current IME (Input Method Editor) name.">
<intent
android:targetClass="org.retroarch.browser.ReportIME"
android:targetPackage="org.retroarch" />
</Preference>
</PreferenceCategory>
</PreferenceScreen>
<PreferenceScreen android:title="Path Options">
<PreferenceCategory android:title="ROM paths">
<Preference android:title="ROM directory"
android:summary="Sets directory where ROM browser will first browse for ROM files.">
<intent
android:targetClass="org.retroarch.browser.ROMDirActivity"
android:targetPackage="org.retroarch" />
</Preference>
</PreferenceCategory>
<PreferenceCategory android:title="Save files">
<CheckBoxPreference android:title="Enable custom directory"
android:summary="Enables use of custom save file folder. (.srm) save files will be saved and loaded to configured directory. If not enabled, save files will reside in ROM folder."
android:key="savefile_directory_enable"
android:defaultValue="false"/>
<Preference android:title="Savefile directory"
android:summary="Sets directory where to save and load game save files."
android:dependency="savefile_directory_enable">
<intent
android:targetClass="org.retroarch.browser.SRMDirActivity"
android:targetPackage="org.retroarch" />
</Preference>
</PreferenceCategory>
<PreferenceCategory android:title="Save states">
<CheckBoxPreference android:title="Enable custom directory"
android:summary="Enables use of custom save state folder. (.state) save states will be saved and loaded to configured directory. If not enabled, save states will reside in ROM folder."
android:key="savestate_directory_enable"
android:defaultValue="false"/>
<Preference android:title="Save state directory"
android:summary="Sets directory where to save and load game save states."
android:dependency="savestate_directory_enable">
<intent
android:targetClass="org.retroarch.browser.StateDirActivity"
android:targetPackage="org.retroarch" />
</Preference>
</PreferenceCategory>
<PreferenceCategory android:title="System">
<CheckBoxPreference android:title="Enable custom directory"
android:summary="Enables use of custom system folder. Cores will look for system specific files, like BIOSes, in this folder. If not enabled, it will look in the ROM folder."
android:key="system_directory_enable"
android:defaultValue="false"/>
<Preference android:title="System directory"
android:summary="Sets directory where system files are loaded from."
android:dependency="system_directory_enable">
<intent
android:targetClass="org.retroarch.browser.SystemDirActivity"
android:targetPackage="org.retroarch" />
</Preference>
</PreferenceCategory>
</PreferenceScreen>
<PreferenceScreen android:title="Settings" >
<PreferenceCategory android:title="General" >
<CheckBoxPreference
android:defaultValue="true"
android:key="savestate_auto_load"
android:summary="Loads an automatically created savestate (*.state.auto) at startup."
android:title="Auto load state" />
<CheckBoxPreference
android:defaultValue="false"
android:key="savestate_auto_save"
android:summary="Automatically saves state (*.state.auto) when exiting game."
android:title="Auto save state" />
</PreferenceCategory>
<PreferenceCategory android:title="Rewinding" >
<CheckBoxPreference
android:defaultValue="false"
android:key="rewind_enable"
android:summary="Enable real-time rewinding of gameplay. (WARNING: Very CPU intensive - will decrease ingame performance by a lot - only use this option on a powerful device)."
android:title="Enable" />
</PreferenceCategory>
</PreferenceScreen>
<PreferenceScreen android:title="Help">
<intent
android:targetClass="org.retroarch.browser.HelpActivity"
android:targetPackage="org.retroarch" />
</PreferenceScreen>
<PreferenceScreen android:title="About">
<PreferenceCategory android:title="Websites">
<Preference android:title="RetroArch/libretro homepage"
android:summary="The official homepage of the RetroArch/libretro project.">
<intent
android:action="android.intent.action.VIEW"
android:data="http://www.libretro.com" />
</Preference>
</PreferenceCategory>
<PreferenceCategory android:title="Manuals">
<Preference android:title="RetroArch Guide (PDF)"
android:summary="The manual to RetroArch Android in PDF format.">
<intent
android:action="android.intent.action.VIEW"
android:data="http://www.libretro.com/documents/retroarch-manual.pdf" />
</Preference>
<Preference android:title="Cores Guide (PDF)"
android:summary="The manual to most libretro cores in PDF format.">
<intent
android:action="android.intent.action.VIEW"
android:data="http://www.libretro.com/documents/retroarch-cores-manual.pdf" />
</Preference>
</PreferenceCategory>
<PreferenceCategory android:title="Development">
<Preference android:title="Overlay Guide (PDF)"
android:summary="Explains howto make your own overlays.">
<intent
android:action="android.intent.action.VIEW"
android:data="http://www.libretro.com/documents/overlay.pdf" />
</Preference>
</PreferenceCategory>
</PreferenceScreen>
</PreferenceScreen>

View File

@ -0,0 +1,97 @@
package org.retroarch.browser;
import org.retroarch.R;
import java.io.*;
import android.app.*;
import android.media.AudioManager;
import android.os.*;
import android.widget.*;
import android.util.Log;
import android.view.*;
// JELLY_BEAN_MR1 = 17
public class CoreSelection extends Activity implements
AdapterView.OnItemClickListener {
private IconAdapter<ModuleWrapper> adapter;
static private final String TAG = "CoreSelection";
@Override
public void onCreate(Bundle savedInstanceState) {
ConfigFile core_config;
super.onCreate(savedInstanceState);
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 = MainMenuActivity.readCPUInfo();
boolean cpuIsNeon = cpuInfo.contains("neon");
setContentView(R.layout.line_list);
// Setup the list
adapter = new IconAdapter<ModuleWrapper>(this, R.layout.line_list_item);
ListView list = (ListView) findViewById(R.id.list);
list.setAdapter(adapter);
list.setOnItemClickListener(this);
setTitle("Select Libretro core");
// Populate the list
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")) {
boolean hasNeonVersion = false;
for (final File lib_ : libs) {
String otherName = lib_.getName();
String baseName = libName.replace(".so", "");
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")) {
try {
adapter.add(new ModuleWrapper(this, lib, core_config));
} catch (IOException e) {
e.printStackTrace();
}
}
}
this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
}
@Override
public void onItemClick(AdapterView<?> aListView, View aView,
int aPosition, long aID) {
final ModuleWrapper item = adapter.getItem(aPosition);
MainMenuActivity.getInstance().setModule(item.file.getAbsolutePath(), item.getText());
MainMenuActivity.getInstance().updateConfigFile();
finish();
}
}

View File

@ -12,75 +12,7 @@ import android.os.*;
import android.preference.PreferenceManager;
import android.widget.*;
import android.view.*;
import android.graphics.drawable.*;
class FileWrapper implements IconAdapterItem {
public final File file;
public final boolean parentItem;
public final boolean dirSelectItem;
protected final boolean enabled;
public static final int DIRSELECT = 0;
public static final int PARENT = 1;
public static final int FILE = 2;
protected final int typeIndex;
public FileWrapper(File aFile, int type, boolean aIsEnabled) {
file = aFile;
parentItem = type == PARENT;
dirSelectItem = type == DIRSELECT;
typeIndex = type == FILE ? (FILE + (file.isDirectory() ? 0 : 1)) : type;
enabled = parentItem || dirSelectItem || aIsEnabled;
}
@Override
public boolean isEnabled() {
return enabled;
}
@Override
public String getText() {
if (dirSelectItem)
return "[[Use this directory]]";
else if (parentItem)
return "[Parent Directory]";
else
return file.getName();
}
@Override
public int getIconResourceId() {
if (!parentItem && !dirSelectItem) {
return file.isFile() ? R.drawable.ic_file : R.drawable.ic_dir;
} else {
return R.drawable.ic_dir;
}
}
@Override
public Drawable getIconDrawable() {
return null;
}
public int compareTo(FileWrapper aOther) {
if (aOther != null) {
// Who says ternary is hard to follow
if (isEnabled() == aOther.isEnabled()) {
return (typeIndex == aOther.typeIndex) ? file
.compareTo(aOther.file)
: ((typeIndex < aOther.typeIndex) ? -1 : 1);
} else {
return isEnabled() ? -1 : 1;
}
}
return -1;
}
}
public class DirectoryActivity extends Activity implements
AdapterView.OnItemClickListener {

View File

@ -0,0 +1,80 @@
package org.retroarch.browser;
import java.io.File;
import org.retroarch.R;
import android.graphics.drawable.Drawable;
class FileWrapper implements IconAdapterItem {
public final File file;
public final boolean parentItem;
public final boolean dirSelectItem;
protected final boolean enabled;
public static final int DIRSELECT = 0;
public static final int PARENT = 1;
public static final int FILE = 2;
protected final int typeIndex;
public FileWrapper(File aFile, int type, boolean aIsEnabled) {
file = aFile;
parentItem = type == PARENT;
dirSelectItem = type == DIRSELECT;
typeIndex = type == FILE ? (FILE + (file.isDirectory() ? 0 : 1)) : type;
enabled = parentItem || dirSelectItem || aIsEnabled;
}
@Override
public boolean isEnabled() {
return enabled;
}
@Override
public String getText() {
if (dirSelectItem)
return "[[Use this directory]]";
else if (parentItem)
return "[Parent Directory]";
else
return file.getName();
}
@Override
public String getSubText() {
return null;
}
@Override
public int getIconResourceId() {
if (!parentItem && !dirSelectItem) {
return file.isFile() ? R.drawable.ic_file : R.drawable.ic_dir;
} else {
return R.drawable.ic_dir;
}
}
@Override
public Drawable getIconDrawable() {
return null;
}
public int compareTo(FileWrapper aOther) {
if (aOther != null) {
// Who says ternary is hard to follow
if (isEnabled() == aOther.isEnabled()) {
return (typeIndex == aOther.typeIndex) ? file
.compareTo(aOther.file)
: ((typeIndex < aOther.typeIndex) ? -1 : 1);
} else {
return isEnabled() ? -1 : 1;
}
}
return -1;
}
}

View File

@ -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<HistoryWrapper> adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.line_list);
// Setup the list
adapter = new IconAdapter<HistoryWrapper>(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();
}
}

View File

@ -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;
}
}

View File

@ -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<T extends IconAdapterItem> extends ArrayAdapter<T> {
public IconAdapter(Activity aContext, int aLayout) {
super(aContext, aLayout);
layout = aLayout;
}
@ -45,6 +42,16 @@ class IconAdapter<T extends IconAdapterItem> extends ArrayAdapter<T> {
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) {

View File

@ -0,0 +1,726 @@
package org.retroarch.browser;
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.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.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;
@SuppressWarnings("deprecation")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
instance = this;
addPreferencesFromResource(R.xml.prefs);
PreferenceManager.setDefaultValues(this, R.xml.prefs, false);
this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
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.")
.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();
}
}
if (prefs.getString("libretro_path", "").isEmpty() == false) {
libretro_path = prefs.getString("libretro_path", "");
setCoreTitle("No core");
if (prefs.getString("libretro_name", "").isEmpty() == false) {
libretro_name = prefs.getString("libretro_name", "No core");
setCoreTitle(libretro_name);
}
} else {
libretro_path = MainMenuActivity.getInstance().getApplicationInfo().nativeLibraryDir;
libretro_name = "No core";
setCoreTitle("No core");
}
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 = PreferenceManager
.getDefaultSharedPreferences(MainMenuActivity.getInstance()
.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 = MainMenuActivity.getInstance().getDisplayRefreshRate();
}
} else {
rate = MainMenuActivity.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) MainMenuActivity.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) MainMenuActivity.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: " + buffersize);
return buffersize;
}
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;
}
public static String getDefaultConfigPath() {
String internal = System.getenv("INTERNAL_STORAGE");
String external = System.getenv("EXTERNAL_STORAGE");
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(MainMenuActivity.getInstance()
.getBaseContext());
boolean global_config_enable = prefs.getBoolean("global_config_enable",
true);
boolean config_same_as_native_lib_dir = libretro_path
.equals(MainMenuActivity.getInstance().getApplicationInfo().nativeLibraryDir);
String append_path;
if (!global_config_enable && (config_same_as_native_lib_dir == false)) {
String sanitized_name = libretro_path.substring(
libretro_path.lastIndexOf("/") + 1,
libretro_path.lastIndexOf("."));
sanitized_name = sanitized_name.replace("neon", "");
sanitized_name = sanitized_name.replace("libretro_", "");
append_path = File.separator + sanitized_name + "retroarch.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 ((MainMenuActivity.getInstance().getApplicationInfo().dataDir) != null)
return (MainMenuActivity.getInstance().getApplicationInfo().dataDir)
+ append_path;
else
// emergency fallback, all else failed
return "/mnt/sd" + append_path;
}
public void updateConfigFile() {
ConfigFile config;
try {
config = new ConfigFile(new File(getDefaultConfigPath()));
} catch (IOException e) {
config = new ConfigFile();
}
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(MainMenuActivity.getInstance()
.getBaseContext());
config.setString("libretro_path", libretro_path);
config.setString("libretro_name", libretro_name);
setCoreTitle(libretro_name);
config.setString("rgui_browser_directory",
prefs.getString("rgui_browser_directory", ""));
config.setBoolean("global_config_enable",
prefs.getBoolean("global_config_enable", true));
config.setBoolean("audio_rate_control",
prefs.getBoolean("audio_rate_control", true));
config.setInt("audio_out_rate",
MainMenuActivity.getOptimalSamplingRate());
int buffersize = 0;
if (android.os.Build.VERSION.SDK_INT >= 17) {
buffersize = getLowLatencyBufferSize();
if (config.getBoolean("audio_high_latency") == false) {
config.setInt("audio_latency", buffersize / 32);
} else {
config.setInt("audio_latency",
prefs.getBoolean("audio_high_latency", false) ? 160 : 64);
}
}
else {
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",
MainMenuActivity.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", (MainMenuActivity.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", MainMenuActivity.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));
}
}
String confPath = getDefaultConfigPath();
try {
config.write(new File(confPath));
} catch (IOException e) {
Log.e(TAG, "Failed to save config file to: " + confPath);
}
}
private byte[] loadAsset(String asset) throws IOException {
String path = asset;
InputStream stream = getAssets().open(path);
int len = stream.available();
byte[] buf = new byte[len];
stream.read(buf, 0, len);
return buf;
}
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);
for (final String path : paths)
extractAssets(manager, dataDir, relativePath
+ (level > 0 ? File.separator : "") + path, level + 1);
} else { // File, extract.
// 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)));
writer.write(asset, 0, asset.length);
writer.flush();
writer.close();
}
}
private int getVersionCode() {
int version = 0;
try {
version = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode;
} catch (NameNotFoundException e) {
}
return version;
}
private boolean areAssetsExtracted() {
int version = getVersionCode();
try {
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));
int currentCacheVersion = 0;
try {
currentCacheVersion = cacheStream.readInt();
} catch (IOException e) {
}
cacheStream.close();
if (currentCacheVersion == version) {
Log.i("ASSETS", "Assets already extracted, skipping...");
return true;
}
}
} 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(getVersionCode());
outputCacheVersion.close();
} catch (IOException e) {
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();
}
public void setModule(String core_path, String core_name) {
libretro_path = core_path;
libretro_name = core_name;
File libretro_path_file = new File(core_path);
setCoreTitle((libretro_path_file.isDirectory() == true) ? "No core"
: core_name);
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(getBaseContext());
SharedPreferences.Editor edit = prefs.edit();
edit.putString("libretro_path", libretro_path);
edit.putString("libretro_name", libretro_name);
edit.commit();
}
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")) {
AlertDialog.Builder alert = new AlertDialog.Builder(this)
.setTitle("NVidia Shield detected")
.setMessage(message)
.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();
}
});
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 = PreferenceManager
.getDefaultSharedPreferences(getBaseContext());
SharedPreferences.Editor edit = prefs
.edit();
edit.putBoolean("input_overlay_enable",
false);
edit.putBoolean("input_autodetect_enable",
true);
edit.putBoolean("audio_high_latency", true);
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 = 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(message)
.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();
}
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",
MainMenuActivity.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);
}
}

View File

@ -0,0 +1,50 @@
package org.retroarch.browser;
import java.io.File;
import java.io.IOException;
import android.content.Context;
import android.graphics.drawable.Drawable;
class ModuleWrapper implements IconAdapterItem {
public final File file;
private ConfigFile config;
public ModuleWrapper(Context aContext, File aFile, ConfigFile config) throws IOException {
file = aFile;
this.config = config;
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public String getText() {
String stripped = file.getName().replace(".so", "");
if (config.keyExists(stripped)) {
return config.getString(stripped);
} 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() {
return 0;
}
@Override
public Drawable getIconDrawable() {
return null;
}
}

View File

@ -7,7 +7,7 @@ import android.os.Bundle;
public class OverlayActivity extends DirectoryActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
File overlayDir = new File(getCacheDir(), "Overlays");
File overlayDir = new File(getBaseContext().getApplicationInfo().dataDir, "overlays");
if (overlayDir.exists())
super.setStartDirectory(overlayDir.getAbsolutePath());

View File

@ -11,7 +11,7 @@ public class ROMActivity extends DirectoryActivity {
public void onCreate(Bundle savedInstanceState) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
String startPath = prefs.getString("phoenix_rom_dir", "");
String startPath = prefs.getString("rgui_browser_directory", "");
if (!startPath.isEmpty() && new File(startPath).exists())
super.setStartDirectory(startPath);

View File

@ -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);
}

View File

@ -0,0 +1,15 @@
package org.retroarch.browser;
import android.app.Activity;
import android.app.AlertDialog;
import android.os.Bundle;
import android.provider.Settings;
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();
}
}

View File

@ -4,21 +4,37 @@ import android.app.NativeActivity;
import android.os.Bundle;
import android.widget.Toast;
public class RetroActivity extends NativeActivity
{
public RetroActivity()
{
public class RetroActivity extends NativeActivity {
public RetroActivity() {
super();
}
@Override
public void onCreate(Bundle savedInstance)
{
public void onCreate(Bundle savedInstance) {
super.onCreate(savedInstance);
}
@Override
public void onLowMemory()
{
public void onLowMemory() {
}
@Override
public void onTrimMemory(int level) {
}
// We call this function from native to display a toast string
public void showToastAlert(String text)
{
// We need to use a runnable here to ensure that when the spawned
// native_app_glue thread calls, we actually post the work to the UI
// thread. Otherwise, we'll likely get exceptions because there's no
// prepared Looper on the native_app_glue main thread.
final String finalText = text;
runOnUiThread(new Runnable() {
public void run()
{
Toast.makeText(getApplicationContext(), finalText, Toast.LENGTH_SHORT).show();
}
});
}
}

View File

@ -1,673 +0,0 @@
package org.retroarch.browser;
import org.retroarch.R;
import java.io.*;
import android.content.*;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetManager;
import android.annotation.TargetApi;
import android.app.*;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.net.Uri;
import android.os.*;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.widget.*;
import android.util.Log;
import android.view.*;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.inputmethod.*;
import android.graphics.drawable.*;
class ModuleWrapper implements IconAdapterItem {
public final File file;
private ConfigFile config;
public ModuleWrapper(Context aContext, File aFile, ConfigFile config) throws IOException {
file = aFile;
this.config = config;
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public String getText() {
String stripped = file.getName().replace(".so", "");
if (config.keyExists(stripped)) {
return config.getString(stripped);
} else
return stripped;
}
@Override
public int getIconResourceId() {
return 0;
}
@Override
public Drawable getIconDrawable() {
return null;
}
}
public class RetroArch extends Activity implements
AdapterView.OnItemClickListener {
private IconAdapter<ModuleWrapper> adapter;
static private final int ACTIVITY_LOAD_ROM = 0;
static private String libretro_path;
static private Double report_refreshrate;
static private final String TAG = "RetroArch-Phoenix";
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");
}
private byte[] loadAsset(String asset) throws IOException {
String path = asset;
InputStream stream = getAssets().open(path);
int len = stream.available();
byte[] buf = new byte[len];
stream.read(buf, 0, len);
return buf;
}
private void extractAssets(AssetManager manager, String cacheDir, 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);
for (final String path : paths)
extractAssets(manager, cacheDir, relativePath + (level > 0 ? File.separator : "") + path, level + 1);
} else { // File, extract.
//Log.d(TAG, "Extracting assets file: " + relativePath);
String parentPath = new File(relativePath).getParent();
if (parentPath != null) {
File parentFile = new File(cacheDir, parentPath);
parentFile.mkdirs(); // Doesn't throw.
}
byte[] asset = loadAsset(relativePath);
BufferedOutputStream writer = new BufferedOutputStream(
new FileOutputStream(new File(cacheDir, relativePath)));
writer.write(asset, 0, asset.length);
writer.flush();
writer.close();
}
}
private void extractAssets() {
int version = 0;
try {
version = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode;
} catch(NameNotFoundException e) {
// weird exception, shouldn't happen
}
try {
AssetManager assets = getAssets();
String cacheDir = getCacheDir().getAbsolutePath();
File cacheVersion = new File(cacheDir, ".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)
{
Log.i("ASSETS", "Assets already extracted, skipping...");
return;
}
}
//extractAssets(assets, cacheDir, "", 0);
Log.i("ASSETS", "Extracting shader assets now ...");
try {
extractAssets(assets, cacheDir, "Shaders", 1);
} catch (IOException e) {
Log.i("ASSETS", "Failed to extract shaders ...");
}
Log.i("ASSETS", "Extracting overlay assets now ...");
try {
extractAssets(assets, cacheDir, "Overlays", 1);
} catch (IOException e) {
Log.i("ASSETS", "Failed to extract overlays ...");
}
DataOutputStream outputCacheVersion = new DataOutputStream(new FileOutputStream(cacheVersion, false));
outputCacheVersion.writeInt(version);
outputCacheVersion.close();
} catch (IOException e) {
Log.e(TAG, "Failed to extract assets to cache.");
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
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);
report_refreshrate = getDisplayRefreshRate();
// 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();
setContentView(R.layout.line_list);
// Setup the list
adapter = new IconAdapter<ModuleWrapper>(this, R.layout.line_list_item);
ListView list = (ListView) findViewById(R.id.list);
list.setAdapter(adapter);
list.setOnItemClickListener(this);
setTitle("Select Libretro core");
// Populate the list
final String modulePath = 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")) {
boolean hasNeonVersion = false;
for (final File lib_ : libs) {
String otherName = lib_.getName();
String baseName = libName.replace(".so", "");
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")) {
try {
adapter.add(new ModuleWrapper(this, lib, core_config));
} catch (IOException e) {
e.printStackTrace();
}
}
}
this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
this.registerForContextMenu(findViewById(android.R.id.content));
}
}
@Override
protected void onStart() {
super.onStart();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
if (!prefs.getBoolean("first_time_refreshrate_calculate", false)) {
prefs.edit().putBoolean("first_time_refreshrate_calculate", true).commit();
AlertDialog.Builder alert = new AlertDialog.Builder(this)
.setTitle("Calculate Refresh Rate")
.setMessage("It is highly recommended you run the refresh rate calibration test before you use RetroArch. Do you want to run it now?\n\nIf you choose No, you can run it at any time in the video preferences.\n\nIf you get performance problems even after calibration, please try threaded video driver in video preferences.")
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent i = new Intent(getBaseContext(), DisplayRefreshRateTest.class);
startActivity(i);
}
})
.setNegativeButton("No", null);
alert.show();
}
}
@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 (getCacheDir() != null && getCacheDir().getAbsolutePath() != null)
return getCacheDir().getAbsolutePath() + File.separator + "retroarch.cfg";
else // emergency fallback, all else failed
return "/mnt/sd/retroarch.cfg";
}
@TargetApi(android.os.Build.VERSION_CODES.JELLY_BEAN_MR1)
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 >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1)
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.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", false));
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", getCacheDir() + "/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;
case R.id.rarch_settings:
Intent rset = new Intent(this, SettingsActivity.class);
startActivity(rset);
return true;
case R.id.help:
Intent help = new Intent(this, HelpActivity.class);
startActivity(help);
return true;
case R.id.report_ime:
String current_ime = Settings.Secure.getString(getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
new AlertDialog.Builder(this).setMessage(current_ime).setNeutralButton("Close", null).show();
return true;
case R.id.report_refreshrate:
String current_rate = "Screen Refresh Rate: " + Double.valueOf(report_refreshrate).toString();
new AlertDialog.Builder(this).setMessage(current_rate).setNeutralButton("Close", null).show();
return true;
case R.id.retroarch_guide:
Intent rguide = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.libretro.org/documents/retroarch-manual.pdf"));
startActivity(rguide);
return true;
case R.id.cores_guide:
Intent cguide = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.libretro.org/documents/retroarch-cores-manual.pdf"));
startActivity(cguide);
return true;
case R.id.overlay_guide:
Intent mguide = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.libretro.org/documents/overlay.pdf"));
startActivity(mguide);
return true;
default:
return false;
}
}
}
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);
}
}
@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();
}
}
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();
}
}
}

View File

@ -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();
}
}

View File

@ -1,19 +0,0 @@
package org.retroarch.browser;
import org.retroarch.R;
import android.media.AudioManager;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceManager;
public class SettingsActivity extends PreferenceActivity {
@SuppressWarnings("deprecation")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.prefs);
PreferenceManager.setDefaultValues(this, R.xml.prefs, false);
this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
}
}

View File

@ -7,7 +7,7 @@ import android.os.Bundle;
public class ShaderActivity extends DirectoryActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
File shaderDir = new File(getCacheDir(), "Shaders");
File shaderDir = new File(getBaseContext().getApplicationInfo().dataDir, "shaders_glsl");
if (shaderDir.exists())
super.setStartDirectory(shaderDir.getAbsolutePath());

View File

@ -16,40 +16,67 @@
#include <IOKit/hid/IOHIDManager.h>
#include "../RetroArch/apple_input.h"
// NOTE: I pieced this together through trial and error, any corrections are welcome
static IOHIDManagerRef g_hid_manager;
static uint32_t g_num_pads;
static void hid_input_callback(void* inContext, IOReturn inResult, void* inSender, IOHIDValueRef inIOHIDValueRef)
{
IOHIDElementRef element = IOHIDValueGetElement(inIOHIDValueRef);
uint32_t slot = (uint32_t)inContext;
if (slot >= 4)
return;
IOHIDDeviceRef device = IOHIDElementGetDevice(element);
uint32_t type = IOHIDElementGetType(element);
uint32_t page = IOHIDElementGetUsagePage(element);
uint32_t use = IOHIDElementGetUsage(element);
if (type == 2 && page == 9)
// Mouse handler
if (IOHIDDeviceConformsTo(device, kHIDPage_GenericDesktop, kHIDUsage_GD_Mouse))
{
CFIndex state = IOHIDValueGetIntegerValue(inIOHIDValueRef);
if (state) g_current_input_data.pad_buttons[slot] |= (1 << (use - 1));
else g_current_input_data.pad_buttons[slot] &= ~(1 << (use - 1));
}
else if (page == 1)
{
static const uint32_t axis_use_ids[4] = { 48, 49, 50, 53 };
for (int i = 0; i < 4; i ++)
if (type == kIOHIDElementTypeInput_Button && page == kHIDPage_Button)
{
if (use == axis_use_ids[i])
CFIndex state = IOHIDValueGetIntegerValue(inIOHIDValueRef);
if (state) g_current_input_data.mouse_buttons |= (1 << (use - 1));
else g_current_input_data.mouse_buttons &= ~(1 << (use - 1));
}
else if (type == kIOHIDElementTypeInput_Misc && page == kHIDPage_GenericDesktop)
{
static const uint32_t axis_use_ids[2] = { 48, 49 };
for (int i = 0; i < 2; i ++)
if (use == axis_use_ids[i])
g_current_input_data.mouse_delta[i] += IOHIDValueGetIntegerValue(inIOHIDValueRef);
}
}
// Joystick handler
else if (IOHIDDeviceConformsTo(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);
if (state) g_current_input_data.pad_buttons[slot] |= (1 << (use - 1));
else g_current_input_data.pad_buttons[slot] &= ~(1 << (use - 1));
}
else if (type == kIOHIDElementTypeInput_Misc && page == kHIDPage_GenericDesktop)
{
static const uint32_t axis_use_ids[4] = { 48, 49, 50, 53 };
for (int i = 0; i < 4; i ++)
{
CFIndex min = IOHIDElementGetPhysicalMin(element);
CFIndex max = IOHIDElementGetPhysicalMax(element) - min;
CFIndex state = IOHIDValueGetIntegerValue(inIOHIDValueRef) - min;
if (use == axis_use_ids[i])
{
CFIndex min = IOHIDElementGetPhysicalMin(element);
CFIndex max = IOHIDElementGetPhysicalMax(element) - min;
CFIndex state = IOHIDValueGetIntegerValue(inIOHIDValueRef) - min;
float val = (float)state / (float)max;
g_current_input_data.pad_axis[slot][i] = ((val * 2.0f) - 1.0f) * 32767.0f;
float val = (float)state / (float)max;
g_current_input_data.pad_axis[slot][i] = ((val * 2.0f) - 1.0f) * 32767.0f;
}
}
}
}
@ -57,9 +84,18 @@ static void hid_input_callback(void* inContext, IOReturn inResult, void* inSende
static void hid_device_attached(void* inContext, IOReturn inResult, void* inSender, IOHIDDeviceRef inDevice)
{
void* context = 0;
if (IOHIDDeviceConformsTo(inDevice, kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick))
{
if (g_num_pads > 4)
return;
context = (void*)(g_num_pads++);
}
IOHIDDeviceOpen(inDevice, kIOHIDOptionsTypeNone);
IOHIDDeviceScheduleWithRunLoop(inDevice, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
IOHIDDeviceRegisterInputValueCallback(inDevice, hid_input_callback, 0);
IOHIDDeviceRegisterInputValueCallback(inDevice, hid_input_callback, context);
}
static void hid_device_removed(void* inContext, IOReturn inResult, void* inSender, IOHIDDeviceRef inDevice)
@ -67,25 +103,38 @@ static void hid_device_removed(void* inContext, IOReturn inResult, void* inSende
IOHIDDeviceClose(inDevice, kIOHIDOptionsTypeNone);
}
static CFMutableDictionaryRef build_matching_dictionary(uint32_t page, uint32_t use)
{
CFMutableDictionaryRef matcher = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFNumberRef pagen = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page);
CFDictionarySetValue(matcher, CFSTR(kIOHIDDeviceUsagePageKey), pagen);
CFRelease(pagen);
CFNumberRef usen = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &use);
CFDictionarySetValue(matcher, CFSTR(kIOHIDDeviceUsageKey), usen);
CFRelease(usen);
return matcher;
}
void osx_pad_init()
{
if (!g_hid_manager)
{
g_hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
CFMutableDictionaryRef matcher = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
uint32_t page = kHIDPage_GenericDesktop;
uint32_t use = kHIDUsage_GD_Joystick;
CFMutableArrayRef matcher = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
CFNumberRef pagen = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page);
CFDictionarySetValue(matcher, CFSTR(kIOHIDDeviceUsagePageKey), pagen);
CFRelease(pagen);
CFMutableDictionaryRef mouse = build_matching_dictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Mouse);
CFArrayAppendValue(matcher, mouse);
CFRelease(mouse);
CFNumberRef usen = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &use);
CFDictionarySetValue(matcher, CFSTR(kIOHIDDeviceUsageKey), usen);
CFRelease(usen);
CFMutableDictionaryRef joystick = build_matching_dictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick);
CFArrayAppendValue(matcher, joystick);
CFRelease(joystick);
IOHIDManagerSetDeviceMatching(g_hid_manager, matcher);
IOHIDManagerSetDeviceMatchingMultiple(g_hid_manager, matcher);
CFRelease(matcher);
IOHIDManagerRegisterDeviceMatchingCallback(g_hid_manager, hid_device_attached, 0);

42
apple/OSX/platform.h Normal file
View File

@ -0,0 +1,42 @@
/* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef __RARCH_OSX_PLATFORM_H
#define __RARCH_OSX_PLATFORM_H
#import <AppKit/AppKit.h>
@interface RAGameView : NSView
+ (RAGameView*)get;
- (void)display;
@end
@interface RetroArch_OSX : NSObject<RetroArch_Platform, NSApplicationDelegate>
{
@public
NSWindow IBOutlet *window;
}
+ (RetroArch_OSX*)get;
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file;
- (void)unloadingCore:(RAModuleInfo*)core;
@end
#endif

264
apple/OSX/platform.m Normal file
View File

@ -0,0 +1,264 @@
/* 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 <http://www.gnu.org/licenses/>.
*/
#include <pthread.h>
#include <string.h>
#import "RetroArch_Apple.h"
#include "rarch_wrapper.h"
#include "../RetroArch/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
#if defined(USE_XATTR)
#include "sys/xattr.h"
#endif
#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;
[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(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
{
#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(apple_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"];
}
- (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(&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[])
{
return NSApplicationMain(argc, (const char **) argv);
}

View File

@ -31,8 +31,11 @@ static UIView* g_pause_indicator_view;
#elif defined(OSX)
#include "apple_input.h"
static RAGameView* g_instance;
static NSOpenGLContext* g_context;
static NSOpenGLPixelFormat* g_format;
#define g_view g_instance // < RAGameView is a container on iOS; on OSX these are both the same object
@ -55,25 +58,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];
[g_context flushBuffer];
}
- (void)bindDrawable
@ -87,10 +87,33 @@ static float g_screen_scale = 1.0f;
return YES;
}
- (BOOL)isFlipped
{
return YES;
}
- (void)keyDown:(NSEvent*)theEvent
{
}
- (void)mouseDown:(NSEvent*)theEvent
{
g_current_input_data.touch_count = 1;
[self mouseDragged:theEvent];
}
- (void)mouseUp:(NSEvent*)theEvent
{
g_current_input_data.touch_count = 0;
}
- (void)mouseDragged:(NSEvent*)theEvent
{
NSPoint pos = [self convertPoint:[theEvent locationInWindow] fromView:nil];
g_current_input_data.touches[0].screen_x = pos.x;
g_current_input_data.touches[0].screen_y = pos.y;
}
#elif defined(IOS) // < iOS Pause menu and lifecycle
- (id)init
{
@ -164,17 +187,6 @@ 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
@ -190,7 +202,7 @@ bool apple_init_game_view()
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
g_pause_indicator_view.alpha = 1.0f;
[NSObject cancelPreviousPerformRequestsWithTarget:g_instance];
@ -207,13 +219,6 @@ bool apple_init_game_view()
void apple_destroy_game_view()
{
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();
#ifdef IOS
@ -230,6 +235,38 @@ void apple_destroy_game_view()
#endif
}
bool apple_create_gl_context(uint32_t version)
{
#ifdef OSX
[NSOpenGLContext clearCurrentContext];
dispatch_sync(dispatch_get_main_queue(), ^{
[NSOpenGLContext clearCurrentContext];
[g_context clearDrawable];
g_context = nil;
g_format = nil;
NSOpenGLPixelFormatAttribute attributes [] = {
NSOpenGLPFADoubleBuffer, // double buffered
NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)16, // 16 bit depth buffer
version ? NSOpenGLPFAOpenGLProfile : 0, version,
(NSOpenGLPixelFormatAttribute)nil
};
g_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
g_context = [[NSOpenGLContext alloc] initWithFormat:g_format shareContext:nil];
g_context.view = g_view;
[g_context makeCurrentContext];
});
[g_context makeCurrentContext];
#endif
return true;
}
void apple_flip_game_view()
{
if (--g_fast_forward_skips < 0)
@ -248,7 +285,7 @@ void apple_set_game_view_sync(unsigned interval)
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
}
@ -261,6 +298,20 @@ void apple_get_game_view_size(unsigned *width, unsigned *height)
*height = *height ? *height : 480;
}
void *apple_get_proc_address(const char *symbol_name)
{
#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
}
#ifdef IOS
void apple_bind_game_view_fbo(void)
{

View File

@ -27,10 +27,18 @@
@property core_info_t* info;
@property config_file_t* data;
@property (strong) NSString* description;
@property (strong) NSString* customConfigPath;
+ (NSArray*)getModules;
- (bool)supportsFileAtPath:(NSString*)path;
+ (NSString*)globalConfigPath;
- (void)createCustomConfig;
- (void)deleteCustomConfig;
- (bool)hasCustomConfig;
- (NSString*)configPath;
@end
#endif

View File

@ -44,6 +44,9 @@ static core_info_list_t* coreList;
newInfo.data = core->data;
newInfo.description = [NSString stringWithUTF8String:core->display_name];
NSString* baseName = newInfo.path.lastPathComponent.stringByDeletingPathExtension;
newInfo.customConfigPath = [NSString stringWithFormat:@"%@/%@.cfg", apple_platform.retroarchConfigPath, baseName];
[moduleList addObject:newInfo];
}
@ -70,6 +73,37 @@ static core_info_list_t* coreList;
return does_core_support_file(self.info, path.UTF8String);
}
+ (NSString*)globalConfigPath
{
static NSString* path;
if (!path)
path = [NSString stringWithFormat:@"%@/retroarch.cfg", apple_platform.retroarchConfigPath];
return path;
}
- (void)createCustomConfig
{
if (!self.hasCustomConfig)
[NSFileManager.defaultManager copyItemAtPath:RAModuleInfo.globalConfigPath toPath:self.customConfigPath error:nil];
}
- (void)deleteCustomConfig
{
if (self.hasCustomConfig)
[NSFileManager.defaultManager removeItemAtPath:self.customConfigPath error:nil];
}
- (bool)hasCustomConfig
{
return path_file_exists(self.customConfigPath.UTF8String);
}
- (NSString*)configPath
{
return self.hasCustomConfig ? self.customConfigPath : RAModuleInfo.globalConfigPath;
}
@end
#ifdef IOS

View File

@ -18,73 +18,43 @@
#define __RARCH_APPLE_H
#include <Foundation/Foundation.h>
#import <CoreFoundation/CoreFoundation.h>
#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*)retroarchConfigPath; // < This returns the directory that contains retroarch.cfg and other custom configs
- (NSString*)corePath;
@end
#ifdef IOS
#import "../iOS/platform.h"
#elif defined(OSX)
#import "../OSX/platform.h"
#endif
extern bool apple_is_paused;
extern bool apple_is_running;
extern bool apple_use_tv_mode;
extern RAModuleInfo* apple_core;
extern id<RetroArch_Platform> 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<UIApplicationDelegate, UINavigationControllerDelegate, RetroArch_Platform>
+ (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 <AppKit/AppKit.h>
@interface RAGameView : NSOpenGLView
+ (RAGameView*)get;
- (void)display;
@end
@interface RetroArch_OSX : NSObject<RetroArch_Platform, NSApplicationDelegate>
{
@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();
extern void apple_run_core(RAModuleInfo* core, const char* file);
// utility.m
extern void apple_display_alert(NSString* message, NSString* title);
@ -92,4 +62,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

View File

@ -86,6 +86,11 @@ void apple_input_enable_icade(bool on)
icade_buttons = 0;
}
uint32_t apple_input_get_icade_buttons()
{
return icade_enabled ? icade_buttons : 0;
}
void apple_input_handle_key_event(unsigned keycode, bool down)
{
keycode = HIDKEY(keycode);
@ -131,7 +136,10 @@ static void apple_input_poll(void *data)
}
input_joypad_poll(g_joydriver);
g_polled_input_data.pad_buttons[0] |= icade_buttons;
g_polled_input_data.pad_buttons[0] |= apple_input_get_icade_buttons();
g_current_input_data.mouse_delta[0] = 0;
g_current_input_data.mouse_delta[1] = 0;
});
}
@ -147,6 +155,17 @@ static int16_t apple_input_state(void *data, const struct retro_keybind **binds,
case RETRO_DEVICE_KEYBOARD:
return apple_key_pressed(id);
case RETRO_DEVICE_MOUSE:
{
switch (id)
{
case RETRO_DEVICE_ID_MOUSE_X: return g_polled_input_data.mouse_delta[0];
case RETRO_DEVICE_ID_MOUSE_Y: return g_polled_input_data.mouse_delta[1];
case RETRO_DEVICE_ID_MOUSE_LEFT: return g_polled_input_data.mouse_buttons & 1;
case RETRO_DEVICE_ID_MOUSE_RIGHT: return g_polled_input_data.mouse_buttons & 2;
}
}
case RETRO_DEVICE_POINTER:
case RARCH_DEVICE_POINTER_SCREEN:

View File

@ -33,6 +33,9 @@ typedef struct
apple_touch_data_t touches[MAX_TOUCHES];
uint32_t touch_count;
uint32_t mouse_buttons;
int16_t mouse_delta[2];
uint32_t keys[MAX_KEYS];
uint32_t pad_buttons[MAX_PADS];
@ -44,6 +47,7 @@ extern apple_input_data_t g_polled_input_data; //< Game thread data
// Main thread only
void apple_input_enable_icade(bool on);
uint32_t apple_input_get_icade_buttons();
void apple_input_handle_key_event(unsigned keycode, bool down);
#endif

View File

@ -56,7 +56,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;

View File

@ -21,37 +21,13 @@
#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<RetroArch_Platform> 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)
void apple_event_basic_command(void* userdata)
{
switch ((enum basic_event_t)userdata)
{
@ -62,12 +38,12 @@ static void event_basic_command(void* userdata)
}
}
static void event_set_state_slot(void* userdata)
void apple_event_set_state_slot(void* userdata)
{
g_extern.state_slot = (uint32_t)userdata;
}
static void event_show_rgui(void* 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));
@ -83,11 +59,63 @@ static void event_reload_config(void* userdata)
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)
{
// HACK: uninit_drivers is the nuclear option; uninit_audio would be better but will
// crash when resuming.
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()
{
if (apple_is_running)
pthread_mutex_unlock(&stasis_mutex);
}
#pragma mark EMULATION
static pthread_t apple_retro_thread;
static bool apple_is_paused;
static bool apple_is_running;
static RAModuleInfo* apple_core;
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)
{
@ -98,23 +126,31 @@ void apple_run_core(RAModuleInfo* core, const char* 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
static char config_path[PATH_MAX];
static char core_path[PATH_MAX];
static char file_path[PATH_MAX];
static const char* argv[] = { "retroarch", "-c", config_path, "-L", core_path, file_path, 0 };
if (apple_core)
strlcpy(config_path, apple_core.configPath.UTF8String, sizeof(config_path));
else
strlcpy(config_path, RAModuleInfo.globalConfigPath.UTF8String, sizeof(config_path));
if (file && core)
{
load_data->libretro_path = strdup(apple_core.path.UTF8String);
load_data->rom_path = strdup(file);
argv[3] = "-L";
argv[4] = core_path;
strlcpy(core_path, apple_core.path.UTF8String, sizeof(core_path));
strlcpy(file_path, file, sizeof(file_path));
}
else
{
argv[3] = "--menu";
argv[4] = 0;
}
if (pthread_create(&apple_retro_thread, 0, rarch_main, load_data))
if (pthread_create(&apple_retro_thread, 0, rarch_main_spring, argv))
{
apple_rarch_exited((void*)1);
return;
@ -138,574 +174,6 @@ void apple_rarch_exited(void* result)
[apple_platform unloadingCore:used_core];
}
if (use_tv_mode)
if (apple_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

View File

@ -29,6 +29,7 @@ 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);
#ifdef IOS
void apple_bind_game_view_fbo(void);

View File

@ -11,6 +11,7 @@
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 */; };
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 */; };
@ -35,6 +36,8 @@
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; };
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; };
@ -109,6 +112,8 @@
96355CE81788E72A0010DBFA /* RetroArch */ = {
isa = PBXGroup;
children = (
9646869617BBC14E00C5EA69 /* platform.m */,
9646869717BBC14E00C5EA69 /* platform.h */,
9620F662178FD4D3001B3B81 /* settings.m */,
967894A01788F07D00D6CA69 /* griffin.c */,
967894971788F02600D6CA69 /* RAGameView.m */,
@ -214,6 +219,7 @@
9678949F1788F02600D6CA69 /* utility.m in Sources */,
967894A11788F07D00D6CA69 /* griffin.c in Sources */,
9620F663178FD4D3001B3B81 /* settings.m in Sources */,
9646869817BBC14E00C5EA69 /* platform.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -354,7 +360,6 @@
"-D__LIBRETRO__",
"-DRARCH_PERFORMANCE_MODE",
"-DRARCH_MOBILE",
"-DPACKAGE_VERSION=\\\"0.9.9.3\\\"",
"-DHAVE_COREAUDIO",
"-DHAVE_DYNAMIC",
"-DHAVE_OVERLAY",

View File

@ -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 = "<group>"; };
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 = "<group>"; };
966B9CB916E41E7A005B61E1 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = "<group>"; };
966B9CBA16E41E7A005B61E1 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = "<group>"; };
@ -152,6 +154,7 @@
96AFAE3316C1D4EA009DE44C /* RetroArch */ = {
isa = PBXGroup;
children = (
9646869417BBBEAE00C5EA69 /* platform.m */,
967894571788EAAE00D6CA69 /* browser.m */,
967894581788EAAE00D6CA69 /* RALogView.m */,
967894591788EAAE00D6CA69 /* settings.m */,
@ -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;
};
@ -365,7 +369,6 @@
"-D__LIBRETRO__",
"-DRARCH_PERFORMANCE_MODE",
"-DRARCH_MOBILE",
"-DPACKAGE_VERSION=\\\"0.9.9.3\\\"",
"-std=gnu99",
"-DHAVE_COREAUDIO",
"-DHAVE_FBO",
@ -416,7 +419,6 @@
"-D__LIBRETRO__",
"-DRARCH_PERFORMANCE_MODE",
"-DRARCH_MOBILE",
"-DPACKAGE_VERSION=\\\"0.9.9.3\\\"",
"-std=gnu99",
"-DHAVE_COREAUDIO",
"-DHAVE_FBO",
@ -458,7 +460,6 @@
"-D__LIBRETRO__",
"-DRARCH_PERFORMANCE_MODE",
"-DRARCH_MOBILE",
"-DPACKAGE_VERSION=\\\"0.9.9.3\\\"",
"-DHAVE_COREAUDIO",
"-DHAVE_DYNAMIC",
"-DHAVE_OVERLAY",
@ -502,7 +503,6 @@
"-D__LIBRETRO__",
"-DRARCH_PERFORMANCE_MODE",
"-DRARCH_MOBILE",
"-DPACKAGE_VERSION=\\\"0.9.9.3\\\"",
"-DHAVE_COREAUDIO",
"-DHAVE_DYNAMIC",
"-DHAVE_OVERLAY",

View File

@ -36,7 +36,6 @@
NSString* rootPath = RetroArch_iOS.get.documentsDirectory;
NSString* ragPath = [rootPath stringByAppendingPathComponent:@"RetroArchGames"];
RADirectoryList* list = [RADirectoryList directoryListForPath:path_is_directory(ragPath.UTF8String) ? ragPath : rootPath];
return list;
}
@ -156,7 +155,7 @@
cell.imageView.image = [UIImage imageNamed:@"ic_dir"];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
} else {
cell.imageView.image = nil;
cell.imageView.image = [UIImage imageNamed:@"ic_file"];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
}

45
apple/iOS/platform.h Normal file
View File

@ -0,0 +1,45 @@
/* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef __RARCH_IOS_PLATFORM_H
#define __RARCH_IOS_PLATFORM_H
@interface RAGameView : UIViewController
+ (RAGameView*)get;
- (void)openPauseMenu;
- (void)closePauseMenu;
@end
@interface RetroArch_iOS : UINavigationController<UIApplicationDelegate, UINavigationControllerDelegate, RetroArch_Platform>
+ (RetroArch_iOS*)get;
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file;
- (void)unloadingCore:(RAModuleInfo*)core;
- (NSString*)retroarchConfigPath;
- (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
// modes are: keyboard, icade and btstack
void ios_set_bluetooth_mode(NSString* mode);
#endif

347
apple/iOS/platform.m Normal file
View File

@ -0,0 +1,347 @@
/* 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 <http://www.gnu.org/licenses/>.
*/
#include <pthread.h>
#include <string.h>
#import "RetroArch_Apple.h"
#include "rarch_wrapper.h"
#include "../RetroArch/apple_input.h"
#import "views.h"
#include "input/BTStack/btpad.h"
#include "input/BTStack/btdynamic.h"
#include "input/BTStack/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;
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"];
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 (apple_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)applicationDidBecomeActive:(UIApplication *)application
{
apple_exit_stasis();
}
- (void)applicationWillResignActive:(UIApplication *)application
{
apple_enter_stasis();
}
// 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 self.systemDirectory;
}
- (NSString*)corePath
{
return [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"modules"];
}
#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]));
}
}

View File

@ -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.configPath : RAModuleInfo.globalConfigPath;
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",
@ -251,7 +308,7 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
[NSArray arrayWithObjects:@"Input",
subpath_setting(config, @"input_overlay", @"Input Overlay", @"", overlay_path, @"cfg"),
range_setting(config, @"input_overlay_opacity", @"Overlay Opacity", @"1.0", 0.0, 1.0),
range_setting(config, @"overlay_opacity", @"Overlay Opacity", @"1.0", 0.0, 1.0),
group_setting(@"System Keys", [NSArray arrayWithObjects:
// TODO: Many of these strings will be cut off on an iPhone
[NSArray arrayWithObjects:@"System Keys",
@ -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 = [RAModuleInfo getModules];
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,11 +829,11 @@ 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];
}
@ -755,23 +895,25 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
{ "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];
_value->value = [NSString stringWithUTF8String:ios_key_name_map[i].keyname];
[self finish];
return;
}
}
// Pad Buttons
for (int i = 0; g_current_input_data.pad_buttons[_value.player] && i < sizeof(g_current_input_data.pad_buttons[_value.player]) * 8; i++)
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 (g_current_input_data.pad_buttons[_value.player] & (1 << i))
if (buttons & (1 << i))
{
_value.msubValues[1] = [NSString stringWithFormat:@"%d", i];
_value->button_bind = [NSString stringWithFormat:@"%d", i];
[self finish];
return;
}
@ -780,11 +922,11 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
// Pad Axis
for (int i = 0; i < 4; i++)
{
int16_t value = g_current_input_data.pad_axis[_value.player][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];
_value->axis_bind = [NSString stringWithFormat:@"%s%d", (value > 0x1000) ? "+" : "-", i];
[self finish];
break;
}

View File

@ -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"

View File

@ -1,4 +1,4 @@
display_name = "Nintendo DS"
display_name = "Nintendo DS (DeSmuME)"
supported_extensions = "nds"
corename = "DeSmuME"
manufacturer = "Nintendo"

View File

@ -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"

View File

@ -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"

View File

@ -0,0 +1,5 @@
display_name = "PNG Images (InstancingViewer)"
recommended_extensions = "png"
corename = "InstancingViewer"
manufacturer = "Various"
systemname = "Instantiation of objects"

View File

@ -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"

View File

@ -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"

View File

@ -1,4 +1,4 @@
display_name = "Virtual Boy"
display_name = "Virtual Boy (Mednafen VB)"
supported_extensions = "vb|vboy|bin"
corename = "Mednafen VB"
manufacturer = "Nintendo"

View File

@ -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"

View File

@ -1,4 +1,4 @@
display_name = "Modelviewer"
display_name = "3D Models (Modelviewer)"
recommended_extensions = "obj"
corename = "Modelviewer"
manufacturer = "Various"

View File

@ -1,3 +1,3 @@
display_name = "NXEngine (Cave Story)"
display_name = "Cave Story (NXEngine)"
supported_extensions = "exe"
corename = "NXEngine"

View File

@ -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"

View File

@ -1,3 +1,3 @@
display_name = "PrBoom (DOOM)"
display_name = "Doom (PrBoom)"
supported_extensions = "wad|iwad"
corename = "prboom"

View File

@ -1,4 +1,4 @@
display_name = "SceneWalker"
display_name = "3D Models (SceneWalker)"
recommended_extensions = "obj"
corename = "SceneWalker"
manufacturer = "Various"

View File

@ -1,4 +1,4 @@
display_name = "Atari 2600"
display_name = "Atari 2600 (Stella)"
supported_extensions = "a26|bin"
corename = "Stella"
manufacturer = "Atari"

View File

@ -1,3 +1,3 @@
display_name = "TyrQuake"
display_name = "Quake 1 (TyrQuake)"
supported_extensions = "pak"
corename = "prboom"

View File

@ -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

View File

@ -33,13 +33,10 @@
#define SLPlayItf_SetPlayState(a, ...) ((*(a))->SetPlayState(a, __VA_ARGS__))
// TODO: Are these sane?
#define BUFFER_SIZE (2 * 1024)
#define BUFFER_COUNT 16
typedef struct sl
{
uint8_t buffer[BUFFER_COUNT][BUFFER_SIZE];
uint8_t **buffer;
uint8_t *buffer_chunk;
unsigned buffer_index;
unsigned buffer_ptr;
volatile unsigned buffered_blocks;
@ -55,6 +52,7 @@ typedef struct sl
slock_t *lock;
scond_t *cond;
bool nonblock;
unsigned buf_size;
unsigned buf_count;
} sl_t;
@ -93,6 +91,8 @@ static void sl_free(void *data)
if (sl->cond)
scond_free(sl->cond);
free(sl->buffer);
free(sl->buffer_chunk);
free(sl);
}
@ -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: %dms...", 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,11 +124,23 @@ 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);
sl->buf_count = (latency * 4 * out_rate + 500) / 1000;
sl->buf_count = (sl->buf_count + BUFFER_SIZE / 2) / BUFFER_SIZE;
sl->buf_count = min(sl->buf_count, BUFFER_COUNT);
sl->buf_count = (sl->buf_count + sl->buf_size / 2) / sl->buf_size;
RARCH_LOG("[SLES] : Setting audio latency (buffer size: [%d]) ...\n", sl->buf_count * BUFFER_SIZE);
sl->buffer = (uint8_t**)calloc(sizeof(uint8_t*), sl->buf_count);
if (!sl->buffer)
goto error;
sl->buffer_chunk = (uint8_t*)calloc(sl->buf_count, sl->buf_size);
if (!sl->buffer_chunk)
goto error;
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",
sl->buf_size, sl->buf_count, sl->buf_size * sl->buf_count);
fmt_pcm.formatType = SL_DATAFORMAT_PCM;
fmt_pcm.numChannels = 2;
@ -164,7 +178,7 @@ static void *sl_init(const char *device, unsigned rate, unsigned latency)
sl->buffered_blocks = sl->buf_count;
sl->buffer_index = 0;
for (unsigned i = 0; i < sl->buf_count; i++)
(*sl->buffer_queue)->Enqueue(sl->buffer_queue, sl->buffer[i], BUFFER_SIZE);
(*sl->buffer_queue)->Enqueue(sl->buffer_queue, sl->buffer[i], sl->buf_size);
GOTO_IF_FAIL(SLObjectItf_GetInterface(sl->buffer_queue_object, SL_IID_PLAY, &sl->player));
GOTO_IF_FAIL(SLPlayItf_SetPlayState(sl->player, SL_PLAYSTATE_PLAYING));
@ -218,7 +232,7 @@ static ssize_t sl_write(void *data, const void *buf_, size_t size)
slock_unlock(sl->lock);
}
size_t avail_write = min(BUFFER_SIZE - sl->buffer_ptr, size);
size_t avail_write = min(sl->buf_size - sl->buffer_ptr, size);
if (avail_write)
{
memcpy(sl->buffer[sl->buffer_index] + sl->buffer_ptr, buf, avail_write);
@ -228,9 +242,9 @@ static ssize_t sl_write(void *data, const void *buf_, size_t size)
written += avail_write;
}
if (sl->buffer_ptr >= BUFFER_SIZE)
if (sl->buffer_ptr >= sl->buf_size)
{
SLresult res = (*sl->buffer_queue)->Enqueue(sl->buffer_queue, sl->buffer[sl->buffer_index], BUFFER_SIZE);
SLresult res = (*sl->buffer_queue)->Enqueue(sl->buffer_queue, sl->buffer[sl->buffer_index], sl->buf_size);
sl->buffer_index = (sl->buffer_index + 1) % sl->buf_count;
__sync_fetch_and_add(&sl->buffered_blocks, 1);
sl->buffer_ptr = 0;
@ -243,22 +257,26 @@ static ssize_t sl_write(void *data, const void *buf_, size_t size)
}
}
//RARCH_LOG("Blocks: %u\n", sl->buffered_blocks);
return written;
}
static size_t sl_write_avail(void *data)
{
sl_t *sl = (sl_t*)data;
size_t avail = (sl->buf_count - (int)sl->buffered_blocks - 1) * BUFFER_SIZE + (BUFFER_SIZE - (int)sl->buffer_ptr);
size_t avail = (sl->buf_count - (int)sl->buffered_blocks - 1) * sl->buf_size + (sl->buf_size - (int)sl->buffer_ptr);
return avail;
}
static size_t sl_buffer_size(void *data)
{
sl_t *sl = (sl_t*)data;
return BUFFER_SIZE * sl->buf_count;
return sl->buf_size * sl->buf_count;
}
static bool sl_use_float(void *data)
{
(void)data;
return false;
}
const audio_driver_t audio_opensl = {
@ -268,7 +286,7 @@ const audio_driver_t audio_opensl = {
sl_start,
sl_set_nonblock_state,
sl_free,
NULL,
sl_use_float,
"opensl",
sl_write_avail,
sl_buffer_size,

181
audio/thread_wrapper.c Normal file
View File

@ -0,0 +1,181 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2010-2013 - Hans-Kristian Arntzen
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "thread_wrapper.h"
#include "../thread.h"
#include "../general.h"
#include "../performance.h"
#include "../fifo_buffer.h"
#include <stdlib.h>
#include <string.h>
typedef struct audio_thread
{
const audio_driver_t *driver;
void *driver_data;
sthread_t *thread;
slock_t *lock;
scond_t *cond;
bool alive;
bool stopped;
} audio_thread_t;
static void audio_thread_loop(void *data)
{
audio_thread_t *thr = (audio_thread_t*)data;
for (;;)
{
slock_lock(thr->lock);
if (!thr->alive)
{
scond_signal(thr->cond);
slock_unlock(thr->lock);
break;
}
if (thr->stopped)
{
thr->driver->stop(thr->driver_data);
while (thr->stopped)
scond_wait(thr->cond, thr->lock);
thr->driver->start(thr->driver_data);
}
slock_unlock(thr->lock);
g_extern.system.audio_callback();
}
}
static void audio_thread_block(audio_thread_t *thr)
{
slock_lock(thr->lock);
thr->stopped = true;
scond_signal(thr->cond);
slock_unlock(thr->lock);
}
static void audio_thread_unblock(audio_thread_t *thr)
{
slock_lock(thr->lock);
thr->stopped = false;
scond_signal(thr->cond);
slock_unlock(thr->lock);
}
static void audio_thread_free(void *data)
{
audio_thread_t *thr = (audio_thread_t*)data;
slock_lock(thr->lock);
thr->stopped = false;
thr->alive = false;
scond_signal(thr->cond);
slock_unlock(thr->lock);
sthread_join(thr->thread);
thr->driver->free(thr->driver_data);
slock_free(thr->lock);
scond_free(thr->cond);
free(thr);
}
static bool audio_thread_stop(void *data)
{
audio_thread_t *thr = (audio_thread_t*)data;
audio_thread_block(thr);
return true;
}
static bool audio_thread_start(void *data)
{
audio_thread_t *thr = (audio_thread_t*)data;
audio_thread_unblock(thr);
return true;
}
static void audio_thread_set_nonblock_state(void *data, bool state)
{
(void)data;
(void)state;
}
static bool audio_thread_use_float(void *data)
{
audio_thread_t *thr = (audio_thread_t*)data;
return thr->driver->use_float && thr->driver->use_float(thr->driver_data);
}
static ssize_t audio_thread_write(void *data, const void *buf, size_t size)
{
audio_thread_t *thr = (audio_thread_t*)data;
ssize_t ret = thr->driver->write(thr->driver_data, buf, size);
if (ret < 0)
{
slock_lock(thr->lock);
thr->alive = false;
scond_signal(thr->cond);
slock_unlock(thr->lock);
return ret;
}
return ret;
}
static const audio_driver_t audio_thread = {
NULL,
audio_thread_write,
audio_thread_stop,
audio_thread_start,
audio_thread_set_nonblock_state,
audio_thread_free,
audio_thread_use_float,
"audio-thread",
NULL, // No point in using rate control with threaded audio.
NULL,
};
bool rarch_threaded_audio_init(const audio_driver_t **out_driver, void **out_data,
const char *device, unsigned out_rate, unsigned latency,
const audio_driver_t *driver)
{
void *audio_handle = driver->init(device, out_rate, latency);
if (!audio_handle)
return false;
audio_thread_t *thr = (audio_thread_t*)calloc(1, sizeof(*thr));
if (!thr)
{
driver->free(audio_handle);
return false;
}
thr->driver = driver;
thr->driver_data = audio_handle;
thr->cond = scond_new();
thr->lock = slock_new();
thr->alive = true;
thr->stopped = true;
thr->thread = sthread_create(audio_thread_loop, thr);
*out_driver = &audio_thread;
*out_data = thr;
return true;
}

30
audio/thread_wrapper.h Normal file
View File

@ -0,0 +1,30 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2010-2013 - Hans-Kristian Arntzen
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef RARCH_AUDIO_THREAD_H__
#define RARCH_AUDIO_THREAD_H__
#include "../driver.h"
#include "../boolean.h"
// Starts a audio driver in a new thread.
// Access to audio driver will be mediated through this driver.
// This driver interfaces with audio callback and is only used in that case.
bool rarch_threaded_audio_init(const audio_driver_t **out_driver, void **out_data,
const char *device, unsigned out_rate, unsigned latency,
const audio_driver_t *driver);
#endif

View File

@ -77,7 +77,7 @@ static void autosave_thread(void *data)
slock_lock(save->cond_lock);
if (!save->quit)
scond_wait_timeout(save->cond, save->cond_lock, save->interval * 1000);
scond_wait_timeout(save->cond, save->cond_lock, save->interval * 1000000LL);
slock_unlock(save->cond_lock);
}
}

View File

@ -9,7 +9,7 @@ DEFINES += HAVE_RGUI HAVE_NEON RARCH_MOBILE \
SINC_LOWER_QUALITY HAVE_RARCH_MAIN_IMPLEMENTATION \
HAVE_VID_CONTEXT HAVE_FBO HAVE_GRIFFIN __LIBRETRO__ \
HAVE_DYNAMIC HAVE_ZLIB __BLACKBERRY_QNX__ HAVE_OPENGLES \
PACKAGE_VERSION=\"0.9.9\" HAVE_OPENGLES2 HAVE_NULLINPUT \
HAVE_OPENGLES2 HAVE_NULLINPUT \
HAVE_AL HAVE_THREADS WANT_MINIZ HAVE_OVERLAY HAVE_GLSL \
USING_GL20 HAVE_OPENGL __STDC_CONSTANT_MACROS HAVE_BB10

View File

@ -28,6 +28,11 @@ Page
value: 3
}
]
onSelectedValueChanged:
{
ButtonMap.refreshButtonMap(selectedValue)
}
}
actions: [
@ -36,7 +41,7 @@ Page
ActionBar.placement: ActionBarPlacement.OnBar
imageSource: "asset:///images/search.png"
onTriggered: {
RetroArch.discoverController();
RetroArch.discoverController(players.selectedValue);
}
}
]
@ -48,17 +53,39 @@ Page
preferredWidth: 650
horizontalAlignment: HorizontalAlignment.Center
DropDown
Container
{
objectName: "dropdown_devices"
title: "Device"
horizontalAlignment: HorizontalAlignment.Center
layout: StackLayout
{
orientation: LayoutOrientation.LeftToRight
}
DropDown
{
horizontalAlignment: HorizontalAlignment.Left
id: dropdown_device
objectName: "dropdown_devices"
title: "Device"
}
Button
{
horizontalAlignment: HorizontalAlignment.Right
text: "Set"
onClicked:
{
ButtonMap.mapDevice(dropdown_device.selectedValue, players.selectedValue);
}
}
}
ListView
{
id: buttonMapList
objectName: "buttonMapList"
listItemComponents: [
ListItemComponent
{
@ -109,14 +136,13 @@ Page
}
}
]
//TODO: Map specific devices instead of 0.
onTriggered:
{
var sym, data;
data = dataModel.data(indexPath);
sym = RetroArch.mapButton(0, players.selectedValue, data["index"]);
data["button"] = RetroArch.buttonToString(0, sym);
sym = ButtonMap.mapButton(0, players.selectedValue, data["index"]);
data["button"] = ButtonMap.buttonToString(players.selectedValue, sym);
dataModel.replace(indexPath, data);
}

View File

@ -69,7 +69,7 @@
<asset path="../../media/overlays">overlays</asset>
<asset path="assets">assets</asset>
<asset path="assets/images/icon.png">icon.png</asset>
<asset path="../../ios/modules">lib</asset>
<asset path="../../apple/modules">lib</asset>
<!-- Bright theme is used for this application. -->

View File

@ -65,7 +65,7 @@ ButtonMap::ButtonMap(screen_context_t screen_ctx, QString groupId, int coid)
buttonDataModel = new ArrayDataModel();
refreshButtonMap();
refreshButtonMap(0);
}
ButtonMap::~ButtonMap()
@ -78,100 +78,75 @@ QString ButtonMap::getLabel(int button)
return QString((uint)platform_keys[button].joykey);
}
//pass in RARCH button enum for button, map to g_setting
int ButtonMap::mapNextButtonPressed()
{
bps_event_t *event = NULL;
int sym;
int ButtonMap::mapNextButtonPressed()
{
bps_event_t *event = NULL;
int sym;
//use in frontend run loop, get key pressed back, and map
int z = 10;
if (screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_ZORDER, &z) != 0)
{
return -1;
}
//use in frontend run loop, get key pressed back, and map
int z = 10;
if (screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_ZORDER, &z) != 0)
{
return -1;
}
screen_post_window(screen_win, screen_buf, 1, screen_resolution, 0);
screen_post_window(screen_win, screen_buf, 1, screen_resolution, 0);
while(1){
if (BPS_SUCCESS != bps_get_event(&event, -1))
{
fprintf(stderr, "bps_get_event failed\n");
break;
}
while(1)
{
if (BPS_SUCCESS != bps_get_event(&event, -1))
{
fprintf(stderr, "bps_get_event failed\n");
break;
}
if (event)
{
int domain = bps_event_get_domain(event);
if (event)
{
int domain = bps_event_get_domain(event);
if (domain == screen_get_domain())
{
screen_event_t screen_event = screen_event_get_event(event);
int screen_val;
screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TYPE, &screen_val);
if (domain == screen_get_domain())
{
screen_event_t screen_event = screen_event_get_event(event);
int screen_val;
screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TYPE, &screen_val);
//TODO: Should we only let the buttons through that we are trying to map?
if(screen_val == SCREEN_EVENT_MTOUCH_TOUCH)
{
//This is touch screen event
sym = -1;
break;
}
else if(screen_val == SCREEN_EVENT_KEYBOARD)
{
screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_KEY_SYM, &sym);
sym &= 0xFF;
break;
}
else if( (screen_val == SCREEN_EVENT_GAMEPAD) || (screen_val == SCREEN_EVENT_JOYSTICK) )
{
screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_BUTTONS, &sym);
break;
}
}
}
}
//TODO: Should we only let the buttons through that we are trying to map?
if(screen_val == SCREEN_EVENT_MTOUCH_TOUCH)
{
//This is touch screen event
sym = NO_BTN;
break;
}
else if(screen_val == SCREEN_EVENT_KEYBOARD)
{
screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_KEY_SYM, &sym);
sym &= 0xFF;
break;
}
else if( (screen_val == SCREEN_EVENT_GAMEPAD) || (screen_val == SCREEN_EVENT_JOYSTICK) )
{
screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_BUTTONS, &sym);
break;
}
}
}
}
z = -10;
if (screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_ZORDER, &z) != 0) {
return -1;
}
z = -10;
if (screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_ZORDER, &z) != 0)
{
return -1;
}
screen_post_window(screen_win, screen_buf, 1, screen_resolution, 0);
screen_post_window(screen_win, screen_buf, 1, screen_resolution, 0);
return (g_settings.input.binds[player][button].joykey = sym);
}
return (g_settings.input.binds[player][button].joykey = sym);
}
int ButtonMap::getButtonMapping(int player, int button)
{
return g_settings.input.binds[player][button].joykey;
}
QString ButtonMap::buttonToString(int button)
{
for(int i=0;i<20;++i)
{
if(platform_keys[i].joykey == (uint)button)
{
return QString(platform_keys[i].desc);
}
}
return (button!=NO_BTN) ? QString(button) : QString("Not Mapped");
}
int ButtonMap::requestButtonMapping(screen_device_t device, int player, int button)
{
//Send message to run thread to start mapping, wait for reply.
recv_msg msg;
msg.code = RETROARCH_BUTTON_MAP;
this->device = device;
this->player = player;
this->button = button;
return MsgSend(coid, (void*)&msg, sizeof(msg), (void*)NULL, 0);
}
int ButtonMap::getButtonMapping(int player, int button)
{
return g_settings.input.binds[player][button].joykey;
}
void ButtonMap::mapDevice(int index, int player)
{
@ -179,16 +154,16 @@ void ButtonMap::mapDevice(int index, int player)
input_qnx.set_keybinds((void*)&devices[index], devices[index].device, player, 0,
(1ULL << KEYBINDS_ACTION_SET_DEFAULT_BINDS));
refreshButtonMap();
refreshButtonMap(player);
}
void ButtonMap::refreshButtonMap()
{
void ButtonMap::refreshButtonMap(int player)
{
QVariantMap map;
buttonDataModel->clear();
for(int i=0; i<16; ++i)
for (int i=0; i<16; ++i)
{
QString desc = QString(input_config_bind_map[i].desc);
int index = desc.indexOf("(");
@ -198,15 +173,56 @@ void ButtonMap::mapDevice(int index, int player)
}
map.insert("label",QVariant(desc));
map.insert("button", buttonToString(g_settings.input.binds[0][i].joykey));
map.insert("button", buttonToString(player, g_settings.input.binds[player][i].joykey));
map.insert("type", QVariant("item"));
map.insert("index", QVariant(i));
buttonDataModel->append(map);
}
map.insert("label",QVariant("RetroArch Menu"));
map.insert("button", buttonToString(g_settings.input.binds[0][RARCH_MENU_TOGGLE].joykey));
map.insert("button", buttonToString(player, g_settings.input.binds[player][RARCH_MENU_TOGGLE].joykey));
map.insert("type", QVariant("item"));
map.insert("index", QVariant(RARCH_MENU_TOGGLE));
buttonDataModel->append(map);
}
//Update device dropdown
if (deviceSelection)
{
if(port_device[player])
deviceSelection->setSelectedIndex(port_device[player]->index);
else
deviceSelection->resetSelectedIndex();
}
}
//Button map
int ButtonMap::mapButton(int player, int button)
{
recv_msg msg;
msg.code = RETROARCH_BUTTON_MAP;
this->player = player;
this->button = button;
return MsgSend(coid, (void*)&msg, sizeof(msg), (void*)NULL, 0);
}
QString ButtonMap::buttonToString(int player, int button)
{
if(g_settings.input.device[player] == DEVICE_KEYPAD || g_settings.input.device[player] == DEVICE_KEYBOARD)
{
return QString(button);
}
else
{
for(int i=0;i<20;++i)
{
if(platform_keys[i].joykey == (uint)button)
{
return QString(platform_keys[i].desc);
}
}
return (button!=NO_BTN) ? QString(button) : QString("Not Mapped");
}
}

View File

@ -3,6 +3,7 @@
#include <bb/cascades/Application>
#include <bb/cascades/ArrayDataModel>
#include <bb/cascades/DropDown>
#include <screen/screen.h>
#include <sys/neutrino.h>
@ -19,8 +20,9 @@ typedef struct {
using namespace bb::cascades;
class ButtonMap
class ButtonMap: public QObject
{
Q_OBJECT
public:
ButtonMap(screen_context_t screen_cxt, QString groupId, int coid);
@ -33,12 +35,15 @@ public:
int getButtonMapping(int player, int button);
//Call from frontend
int requestButtonMapping(screen_device_t device, int player, int button);
void refreshButtonMap();
void mapDevice(int index, int player);
QString buttonToString(int button);
Q_INVOKABLE int mapButton(int player, int button);
Q_INVOKABLE QString buttonToString(int player, int button);
Q_INVOKABLE void refreshButtonMap(int player);
Q_INVOKABLE void mapDevice(int index, int player);
ArrayDataModel *buttonDataModel;
DropDown *deviceSelection;
private:
screen_context_t screen_cxt;

View File

@ -95,9 +95,10 @@ RetroArch::RetroArch()
screen_create_context(&screen_ctx, 0);
input_qnx.init();
buttonMap = new ButtonMap(screen_ctx, (const char*)Application::instance()->mainWindow()->groupId().toAscii().constData(), coid);
qml->setContextProperty("ButtonMap", buttonMap);
deviceSelection = mAppPane->findChild<DropDown*>("dropdown_devices");
connect(deviceSelection, SIGNAL(selectedValueChanged(QVariant)), this, SLOT(onDeviceSelected(QVariant)));
buttonMap->deviceSelection = deviceSelection;
findDevices();
//Setup the datamodel for button mapping.
@ -257,13 +258,6 @@ void RetroArch::onCoreSelected(QVariant value)
qDebug() << "Supported Extensions: " << romExtensions;
}
void RetroArch::onDeviceSelected(QVariant value)
{
//Change the binds for current player to device[value]
//TODO: Don't hardcode player 0
buttonMap->mapDevice(value.toInt(), 0);
}
/*
* Functions
*/
@ -327,6 +321,16 @@ void RetroArch::findDevices()
}
}
extern "C" void discoverControllers();
void RetroArch::discoverController(int player)
{
//TODO: Check device, gamepad/keyboard and return accordingly.
discoverControllers();
findDevices();
buttonMap->refreshButtonMap(player);
return;
}
void RetroArch::initRASettings()
{
strlcpy(g_settings.libretro,(char *)core.toAscii().constData(), sizeof(g_settings.libretro));
@ -339,28 +343,3 @@ void RetroArch::initRASettings()
if(hwInfo->isPhysicalKeyboardDevice() || port_device[0])
*g_settings.input.overlay = '\0';
}
int RetroArch::mapButton(void* deviceVp, int player, int button)
{
screen_device_t device = (screen_device_t)deviceVp;
return buttonMap->requestButtonMapping(device, player, button);
}
QString RetroArch::buttonToString(void* deviceVp, int button)
{
//TODO: Check deviceVp, gamepad/keyboard and return accordingly.
if(g_settings.input.device[0] == DEVICE_KEYPAD || g_settings.input.device[0] == DEVICE_KEYBOARD)
return QString(button);
else
return buttonMap->buttonToString(button);
}
extern "C" void discoverControllers();
void RetroArch::discoverController()
{
//TODO: Check device, gamepad/keyboard and return accordingly.
discoverControllers();
findDevices();
buttonMap->refreshButtonMap();
return;
}

View File

@ -35,9 +35,7 @@ public:
Q_INVOKABLE void startEmulator();
Q_INVOKABLE void findDevices();
Q_INVOKABLE int mapButton(void* device, int player, int button);
Q_INVOKABLE QString buttonToString(void* deviceVp, int button);
Q_INVOKABLE void discoverController();
Q_INVOKABLE void discoverController(int player);
void populateCores(core_info_list_t * info);
signals:
@ -49,7 +47,6 @@ public slots:
void aboutToQuit();
void onRotationCompleted();
void onCoreSelected(QVariant);
void onDeviceSelected(QVariant);
private:
/**

View File

@ -19,6 +19,7 @@ typedef struct {
char device_name[64];
int device;
int port;
int index;
// Current state.
int buttons;

View File

@ -168,7 +168,7 @@
<listOptionValue builtIn="false" value="HAVE_OPENGLES"/>
<listOptionValue builtIn="false" value="HAVE_OPENGLES2"/>
<listOptionValue builtIn="false" value="HAVE_NULLINPUT"/>
<listOptionValue builtIn="false" value="HAVE_ALSA"/>
<listOptionValue builtIn="false" value="HAVE_AL"/>
<listOptionValue builtIn="false" value="HAVE_THREADS"/>
<listOptionValue builtIn="false" value="WANT_MINIZ"/>
<listOptionValue builtIn="false" value="HAVE_OVERLAY"/>

View File

@ -131,6 +131,8 @@ void discoverControllers()
{
// Get an array of all available devices.
int deviceCount;
screen_event_t *event;
screen_get_context_property_iv(screen_ctx, SCREEN_PROPERTY_DEVICE_COUNT, &deviceCount);
screen_device_t* devices_found = (screen_device_t*)calloc(deviceCount, sizeof(screen_device_t));
screen_get_context_property_pv(screen_ctx, SCREEN_PROPERTY_DEVICES, (void**)devices_found);
@ -151,9 +153,9 @@ void discoverControllers()
if (type == SCREEN_EVENT_GAMEPAD || type == SCREEN_EVENT_JOYSTICK || type == SCREEN_EVENT_KEYBOARD)
{
devices[pads_connected].handle = devices_found[i];
devices[pads_connected].index = pads_connected;
loadController(&devices[pads_connected]);
pads_connected++;
if (pads_connected == MAX_PADS)
break;
}
@ -184,6 +186,7 @@ static void initController(input_device_t* controller)
controller->analog1[0] = controller->analog1[1] = controller->analog1[2] = 0;
controller->port = -1;
controller->device = -1;
controller->index = -1;
memset(controller->id, 0, sizeof(controller->id));
}
@ -225,9 +228,12 @@ static void qnx_input_autodetect_gamepad(input_device_t* controller)
strlcpy(controller->device_name, "None", sizeof(controller->device_name));
}
if (input_qnx.set_keybinds)
if (input_qnx.set_keybinds && (controller->device != DEVICE_NONE))
{
input_qnx.set_keybinds((void*)controller, controller->device, pads_connected, 0,
(1ULL << KEYBINDS_ACTION_SET_DEFAULT_BINDS));
pads_connected++;
}
}
static void process_keyboard_event(screen_event_t event, int type)
@ -730,10 +736,10 @@ static void qnx_input_set_keybinds(void *data, unsigned device, unsigned port,
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_X].def_joykey = KEYCODE_K & 0xFF;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L].def_joykey = KEYCODE_U & 0xFF;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R].def_joykey = KEYCODE_I & 0xFF;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L2].def_joykey = 0;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R2].def_joykey = 0;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L3].def_joykey = 0;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R3].def_joykey = 0;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L2].def_joykey = NO_BTN;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R2].def_joykey = NO_BTN;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L3].def_joykey = NO_BTN;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R3].def_joykey = NO_BTN;
g_settings.input.binds[port][RARCH_MENU_TOGGLE].def_joykey = KEYCODE_P & 0xFF;
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_NONE;
controller->port = port;
@ -756,10 +762,10 @@ static void qnx_input_set_keybinds(void *data, unsigned device, unsigned port,
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_X].def_joykey = KEYCODE_S & 0xFF;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L].def_joykey = KEYCODE_Q & 0xFF;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R].def_joykey = KEYCODE_W & 0xFF;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L2].def_joykey = 0;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R2].def_joykey = 0;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L3].def_joykey = 0;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R3].def_joykey = 0;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L2].def_joykey = NO_BTN;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R2].def_joykey = NO_BTN;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L3].def_joykey = NO_BTN;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R3].def_joykey = NO_BTN;
g_settings.input.binds[port][RARCH_MENU_TOGGLE].def_joykey = KEYCODE_TILDE;
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_NONE;
controller->port = port;
@ -811,7 +817,7 @@ static void qnx_input_set_keybinds(void *data, unsigned device, unsigned port,
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R2].def_joykey = SCREEN_R2_GAME_BUTTON;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L3].def_joykey = SCREEN_L3_GAME_BUTTON;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R3].def_joykey = SCREEN_R3_GAME_BUTTON;
g_settings.input.binds[port][RARCH_MENU_TOGGLE].def_joykey = 0; //TODO: Find a good mappnig
g_settings.input.binds[port][RARCH_MENU_TOGGLE].def_joykey = NO_BTN; //TODO: Find a good mappnig
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_NONE;
controller->port = port;
port_device[port] = controller;
@ -821,23 +827,23 @@ static void qnx_input_set_keybinds(void *data, unsigned device, unsigned port,
strlcpy(g_settings.input.device_names[port], "None",
sizeof(g_settings.input.device_names[port]));
g_settings.input.device[port] = device;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_B].def_joykey = 0;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_Y].def_joykey = 0;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_SELECT].def_joykey = 0;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_START].def_joykey = 0;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_UP].def_joykey = 0;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_DOWN].def_joykey = 0;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_LEFT].def_joykey = 0;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_RIGHT].def_joykey = 0;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_A].def_joykey = 0;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_X].def_joykey = 0;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L].def_joykey = 0;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R].def_joykey = 0;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L2].def_joykey = 0;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R2].def_joykey = 0;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L3].def_joykey = 0;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R3].def_joykey = 0;
g_settings.input.binds[port][RARCH_MENU_TOGGLE].def_joykey = 0;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_B].def_joykey = NO_BTN;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_Y].def_joykey = NO_BTN;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_SELECT].def_joykey = NO_BTN;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_START].def_joykey = NO_BTN;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_UP].def_joykey = NO_BTN;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_DOWN].def_joykey = NO_BTN;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_LEFT].def_joykey = NO_BTN;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_RIGHT].def_joykey = NO_BTN;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_A].def_joykey = NO_BTN;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_X].def_joykey = NO_BTN;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L].def_joykey = NO_BTN;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R].def_joykey = NO_BTN;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L2].def_joykey = NO_BTN;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R2].def_joykey = NO_BTN;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L3].def_joykey = NO_BTN;
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R3].def_joykey = NO_BTN;
g_settings.input.binds[port][RARCH_MENU_TOGGLE].def_joykey = NO_BTN;
controller->port = -1;
port_device[port] = 0;
break;

View File

@ -44,6 +44,7 @@ enum
VIDEO_D3D9,
VIDEO_VG,
VIDEO_NULL,
VIDEO_OMAP,
AUDIO_RSOUND,
AUDIO_OSS,
@ -380,6 +381,9 @@ static const bool savestate_auto_load = true;
// Slowmotion ratio.
static const float slowmotion_ratio = 3.0;
// Maximum fast forward ratio (Negative => no limit).
static const float fastforward_ratio = -1.0;
// Enable stdin/network command interface
static const bool network_cmd_enable = false;
static const uint16_t network_cmd_port = 55355;

1
configure vendored
View File

@ -1,7 +1,6 @@
#!/bin/sh
PACKAGE_NAME=retroarch
PACKAGE_VERSION=0.9.9
cat /dev/null > config.log

6
deps/miniz/miniz.c vendored
View File

@ -706,7 +706,7 @@ struct mz_zip_internal_state_tag
#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size
#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index]
static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray)
static void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray)
{
def_free_func(pZip->m_pAlloc_opaque, pArray->m_p);
memset(pArray, 0, sizeof(mz_zip_array));
@ -721,7 +721,7 @@ static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *
return MZ_TRUE;
}
static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing)
static mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing)
{
if (new_size > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) return MZ_FALSE; }
pArray->m_size = new_size;
@ -748,7 +748,7 @@ static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint32 flags
return MZ_TRUE;
}
static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index)
static mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index)
{
const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE;
const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index));

View File

@ -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
------------------------------------------------------------------------------

View File

@ -24,6 +24,7 @@
#include "audio/utils.h"
#include "audio/resampler.h"
#include "gfx/thread_wrapper.h"
#include "audio/thread_wrapper.h"
#include "gfx/gfx_common.h"
#ifdef HAVE_X11
@ -122,6 +123,9 @@ static const video_driver_t *video_drivers[] = {
#ifdef HAVE_NULLVIDEO
&video_null,
#endif
#ifdef HAVE_OMAP
&video_omap,
#endif
};
static const input_driver_t *input_drivers[] = {
@ -354,7 +358,7 @@ void global_uninit_drivers(void)
if (driver.input_data)
{
driver.input->free(NULL);
driver.input->free(driver.input_data);
driver.input_data = NULL;
}
}
@ -370,19 +374,26 @@ void init_drivers(void)
g_extern.frame_count = 0;
init_video_input();
if (g_extern.system.hw_render_callback.context_reset)
if (!driver.video_cache_context_ack && g_extern.system.hw_render_callback.context_reset)
g_extern.system.hw_render_callback.context_reset();
driver.video_cache_context_ack = false;
init_audio();
// Keep non-throttled state as good as possible.
if (driver.nonblock_state)
driver_set_nonblock_state(driver.nonblock_state);
g_extern.system.frame_time_last = 0;
}
void uninit_drivers(void)
{
uninit_audio();
if (g_extern.system.hw_render_callback.context_destroy && !driver.video_cache_context)
g_extern.system.hw_render_callback.context_destroy();
uninit_video_input();
if (driver.video_data_own)
@ -493,8 +504,26 @@ void init_audio(void)
return;
}
driver.audio_data = audio_init_func(*g_settings.audio.device ? g_settings.audio.device : NULL,
g_settings.audio.out_rate, g_settings.audio.latency);
#ifdef HAVE_THREADS
find_audio_driver();
if (g_extern.system.audio_callback)
{
RARCH_LOG("Starting threaded audio driver ...\n");
if (!rarch_threaded_audio_init(&driver.audio, &driver.audio_data,
*g_settings.audio.device ? g_settings.audio.device : NULL,
g_settings.audio.out_rate, g_settings.audio.latency,
driver.audio))
{
RARCH_ERR("Cannot open threaded audio driver ... Exiting ...\n");
rarch_fail(1, "init_audio()");
}
}
else
#endif
{
driver.audio_data = audio_init_func(*g_settings.audio.device ? g_settings.audio.device : NULL,
g_settings.audio.out_rate, g_settings.audio.latency);
}
if (!driver.audio_data)
{
@ -530,7 +559,8 @@ void init_audio(void)
rarch_assert(g_settings.audio.out_rate < g_settings.audio.in_rate * AUDIO_MAX_RATIO);
rarch_assert(g_extern.audio_data.outsamples = (float*)malloc(outsamples_max * sizeof(float)));
if (g_extern.audio_active && g_settings.audio.rate_control)
g_extern.audio_data.rate_control = false;
if (!g_extern.system.audio_callback && g_extern.audio_active && g_settings.audio.rate_control)
{
if (driver.audio->buffer_size && driver.audio->write_avail)
{
@ -549,6 +579,9 @@ void init_audio(void)
#endif
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.
audio_start_func();
}
static void compute_audio_buffer_statistics(void)
@ -598,10 +631,7 @@ static void compute_audio_buffer_statistics(void)
bool driver_monitor_fps_statistics(double *refresh_rate, double *deviation, unsigned *sample_points)
{
if (g_settings.video.threaded)
{
RARCH_LOG("Monitor FPS estimation is disabled for threaded video.\n");
return false;
}
unsigned samples = min(MEASURE_FRAME_TIME_SAMPLES_COUNT, g_extern.measure_data.frame_time_samples_count);
if (samples < 2)
@ -637,6 +667,12 @@ bool driver_monitor_fps_statistics(double *refresh_rate, double *deviation, unsi
static void compute_monitor_fps_statistics(void)
{
if (g_settings.video.threaded)
{
RARCH_LOG("Monitor FPS estimation is disabled for threaded video.\n");
return;
}
if (g_extern.measure_data.frame_time_samples_count < 2 * MEASURE_FRAME_TIME_SAMPLES_COUNT)
{
RARCH_LOG("Does not have enough samples for monitor refresh rate estimation. Requires to run for at least %u frames.\n",
@ -656,6 +692,9 @@ static void compute_monitor_fps_statistics(void)
void uninit_audio(void)
{
if (driver.audio_data && driver.audio)
driver.audio->free(driver.audio_data);
free(g_extern.audio_data.conv_outsamples);
g_extern.audio_data.conv_outsamples = NULL;
g_extern.audio_data.data_ptr = 0;
@ -669,9 +708,6 @@ void uninit_audio(void)
return;
}
if (driver.audio_data && driver.audio)
driver.audio->free(driver.audio_data);
rarch_resampler_freep(&g_extern.audio_data.resampler, &g_extern.audio_data.resampler_data);
free(g_extern.audio_data.data);

View File

@ -270,6 +270,7 @@ enum input_devices
DEVICE_GAMEMID,
DEVICE_DEFENDER_GAME_RACER_CLASSIC,
DEVICE_HOLTEK_JC_U912F,
DEVICE_NVIDIA_SHIELD,
#elif defined(GEKKO)
DEVICE_GAMECUBE = 0,
#ifdef HW_RVL
@ -301,6 +302,7 @@ enum analog_dpad_bind_enums
ANALOG_DPAD_NONE = 0,
ANALOG_DPAD_LSTICK,
ANALOG_DPAD_RSTICK,
ANALOG_DPAD_DUALANALOG,
ANALOG_DPAD_LAST
};
@ -417,6 +419,11 @@ typedef struct driver
bool threaded_video;
// If set during context deinit, the driver should keep
// graphics context alive to avoid having to reset all context state.
bool video_cache_context;
bool video_cache_context_ack; // Set to true by driver if context caching succeeded.
// Set if the respective handles are owned by RetroArch driver core.
// Consoles upper logic will generally intialize the drivers before
// the driver core initializes. It will then be up to upper logic
@ -516,6 +523,7 @@ extern const video_driver_t video_xdk_d3d;
extern const video_driver_t video_sdl;
extern const video_driver_t video_vg;
extern const video_driver_t video_null;
extern const video_driver_t video_omap;
extern const input_driver_t input_android;
extern const input_driver_t input_sdl;
extern const input_driver_t input_dinput;

View File

@ -28,8 +28,6 @@
#define audio_write_avail_func() driver.audio->write_avail(driver.audio_data)
#define audio_buffer_size_func() driver.audio->buffer_size(driver.audio_data)
#if !defined(RARCH_CONSOLE) /* Normal */
#define video_init_func(video_info, input, input_data) \
driver.video->init(video_info, input, input_data)
#define video_frame_func(data, width, height, pitch, msg) \
@ -69,93 +67,4 @@ static inline bool input_key_pressed_func(int key)
return ret;
}
#else
/*============================================================
VIDEO
============================================================ */
#define CONCAT2(A, B) A##B
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) /* GL */
#define MAKENAME_VIDEO(A) CONCAT2(gl, A)
#define video_set_aspect_ratio_func(aspectratio_idx) gfx_ctx_set_aspect_ratio(driver.video_data, aspectratio_idx)
#define gfx_ctx_window_has_focus() (true)
#elif defined(_XBOX) && (defined(HAVE_D3D8) || defined(HAVE_D3D9)) /* D3D */
#define MAKENAME_VIDEO(A) CONCAT2(xdk_d3d, A)
#elif defined(XENON) /* XENON */
#define MAKENAME_VIDEO(A) CONCAT2(xenon360_gfx, A)
#define video_set_aspect_ratio_func(aspectratio_idx) gfx_ctx_set_aspect_ratio(driver.video_data, aspectratio_idx)
#define gfx_ctx_window_has_focus() (true)
#elif defined(GEKKO) /* Gamecube, Wii */
#define MAKENAME_VIDEO(A) CONCAT2(gx, A)
#define video_set_aspect_ratio_func(aspectratio_idx) gx_set_aspect_ratio(driver.video_data, aspectratio_idx)
#define video_viewport_size_func(width, height) ((void)0)
#define video_read_viewport_func(buffer) (false)
//#elif defined(PSP) /* PSP1 */
//#define MAKENAME_VIDEO(A) CONCAT2(psp, A)
//#define video_set_aspect_ratio_func(aspectratio_idx) (true)
#else /* NULL */
#define MAKENAME_VIDEO(A) CONCAT2(nullvideo, A)
#define video_set_aspect_ratio_func(aspectratio_idx) (true)
#endif
#define video_viewport_info_func(info) driver.video->viewport_info(driver.video_data, info)
#define video_init_func(video_info, input, input_data) MAKENAME_VIDEO(_init)(video_info, input, input_data)
#define video_frame_func(data, width, height, pitch, msg) \
MAKENAME_VIDEO(_frame)(driver.video_data, data, width, height, pitch, msg)
#define video_alive_func() MAKENAME_VIDEO(_alive)(driver.video_data)
#define video_focus_func() MAKENAME_VIDEO(_focus)(driver.video_data)
#define video_free_func() MAKENAME_VIDEO(_free)(driver.video_data)
#define video_set_nonblock_state_func(state) MAKENAME_VIDEO(_set_nonblock_state)(driver.video_data, state)
#define video_set_rotation_func(rotation) MAKENAME_VIDEO(_set_rotation)(driver.video_data, rotation)
#define video_start_func() MAKENAME_VIDEO(_start)()
#define video_set_shader_func(type, path) MAKENAME_VIDEO(_set_shader)(driver.video_data, type, path)
#define video_xml_shader_func(path) driver.video->xml_shader(driver.video_data, path)
/*============================================================
INPUT
============================================================ */
#if defined(_XBOX) && (defined(HAVE_D3D8) || defined(HAVE_D3D9)) /* D3D */
#define MAKENAME_INPUT(A) CONCAT2(xdk, A)
#elif defined(GEKKO) /* Gamecube, Wii */
#define MAKENAME_INPUT(A) CONCAT2(gx, A)
#define gfx_ctx_window_has_focus() (true)
#elif defined(__CELLOS_LV2__) /* PS3 */
#define MAKENAME_INPUT(A) CONCAT2(ps3, A)
#elif defined(ANDROID) /* ANDROID */
#define MAKENAME_INPUT(A) CONCAT2(android, A)
#elif defined(XENON) /* XENON */
#define MAKENAME_INPUT(A) CONCAT2(xenon360, A)
#else
#define MAKENAME_INPUT(A) CONCAT2(nullinput, A)
#endif
#define gfx_ctx_window_has_focus() (true)
#define input_init_func() MAKENAME_INPUT(_input_init)()
#define input_poll_func() MAKENAME_INPUT(_input_poll)(driver.input_data)
#define input_input_state_func(retro_keybinds, port, device, index, id) \
MAKENAME_INPUT(_input_state)(driver.input_data, retro_keybinds, port, device, index, id)
#define input_key_pressed_func(key) MAKENAME_INPUT(_input_key_pressed)(driver.input_data, key)
#define input_free_func() MAKENAME_INPUT(_input_free_input)(driver.input_data)
#define video_overlay_interface_func(iface) driver.video->overlay_interface(driver.video_data, iface)
#endif
#endif /* _RARCH_DRIVER_FUNCS_H */

View File

@ -42,6 +42,7 @@
#endif
#ifdef HAVE_DYNAMIC
#undef SYM
#define SYM(x) do { \
function_t func = dylib_proc(lib_handle, #x); \
memcpy(&p##x, &func, sizeof(func)); \
@ -653,6 +654,7 @@ static bool environment_cb(unsigned cmd, void *data)
break;
case RETRO_ENVIRONMENT_SET_HW_RENDER:
case RETRO_ENVIRONMENT_SET_HW_RENDER | RETRO_ENVIRONMENT_EXPERIMENTAL: // ABI compat
{
RARCH_LOG("Environ SET_HW_RENDER.\n");
struct retro_hw_render_callback *cb = (struct retro_hw_render_callback*)data;
@ -669,6 +671,7 @@ static bool environment_cb(unsigned cmd, void *data)
break;
case RETRO_HW_CONTEXT_OPENGL:
case RETRO_HW_CONTEXT_OPENGL_CORE:
RARCH_ERR("Requesting OpenGL context, but RetroArch is compiled against OpenGLES2. Cannot use HW context.\n");
return false;
#elif defined(HAVE_OPENGL)
@ -680,6 +683,11 @@ static bool environment_cb(unsigned cmd, void *data)
RARCH_LOG("Requesting OpenGL context.\n");
driver.video = &video_gl;
break;
case RETRO_HW_CONTEXT_OPENGL_CORE:
RARCH_LOG("Requesting core OpenGL context (%u.%u).\n", cb->version_major, cb->version_minor);
driver.video = &video_gl;
break;
#endif
default:
@ -688,7 +696,11 @@ static bool environment_cb(unsigned cmd, void *data)
}
cb->get_current_framebuffer = driver_get_current_framebuffer;
cb->get_proc_address = driver_get_proc_address;
memcpy(&g_extern.system.hw_render_callback, cb, sizeof(*cb));
if (cmd & RETRO_ENVIRONMENT_EXPERIMENTAL) // Old ABI. Don't copy garbage.
memcpy(&g_extern.system.hw_render_callback, cb, offsetof(struct retro_hw_render_callback, stencil));
else
memcpy(&g_extern.system.hw_render_callback, cb, sizeof(*cb));
break;
}
@ -711,6 +723,41 @@ static bool environment_cb(unsigned cmd, void *data)
break;
}
#ifdef HAVE_THREADS
case RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK:
{
RARCH_LOG("Environ SET_AUDIO_CALLBACK.\n");
const struct retro_audio_callback *info = (const struct retro_audio_callback*)data;
#ifdef HAVE_FFMPEG
if (g_extern.recording) // A/V sync is a must.
return false;
#endif
#ifdef HAVE_NETPLAY
if (g_extern.netplay_enable)
return false;
#endif
g_extern.system.audio_callback = info->callback;
break;
}
#endif
case RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK:
{
RARCH_LOG("Environ SET_FRAME_TIME_CALLBACK.\n");
#ifdef HAVE_NETPLAY
if (g_extern.netplay_enable) // retro_run() will be called in very strange and mysterious ways, have to disable it.
return false;
#endif
const struct retro_frame_time_callback *info = (const struct retro_frame_time_callback*)data;
g_extern.system.frame_time = *info;
break;
}
default:
RARCH_LOG("Environ UNSUPPORTED (#%u).\n", cmd);
return false;

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