From 5b5743dd9534139416ef6f7cbe9b3a4dcc6758d4 Mon Sep 17 00:00:00 2001 From: Matteo Hausner Date: Fri, 3 Jan 2014 18:32:32 +0100 Subject: [PATCH 1/5] First steps to integrate multi-controller support --- core/hw/maple/maple_cfg.cpp | 7 +- shell/android/jni/src/Android.cpp | 38 ++++++-- .../com/reicast/emulator/GL2JNIActivity.java | 95 +++++++++++++------ .../src/com/reicast/emulator/GL2JNIView.java | 22 +++-- .../src/com/reicast/emulator/JNIdc.java | 4 +- .../src/com/reicast/emulator/MOGAInput.java | 12 +-- 6 files changed, 117 insertions(+), 61 deletions(-) diff --git a/core/hw/maple/maple_cfg.cpp b/core/hw/maple/maple_cfg.cpp index bb294eba3..7757a5217 100644 --- a/core/hw/maple/maple_cfg.cpp +++ b/core/hw/maple/maple_cfg.cpp @@ -69,6 +69,7 @@ void mcfg_Create(MapleDeviceType type,u32 bus,u32 port) void mcfg_CreateDevices() { mcfg_Create(MDT_SegaController,0,5); + mcfg_Create(MDT_SegaController,1,5); #ifdef HAS_VMU mcfg_Create(MDT_SegaVMU,0,0); @@ -78,7 +79,7 @@ void mcfg_CreateDevices() void mcfg_DestroyDevices() { - for (int i=0;i<3;i++) - for (int j=0;j<5;j++) + for (int i=0;i<=3;i++) + for (int j=0;j<=5;j++) delete MapleDevices[i][j]; -} \ No newline at end of file +} diff --git a/shell/android/jni/src/Android.cpp b/shell/android/jni/src/Android.cpp index 3337ac853..f322c0d47 100644 --- a/shell/android/jni/src/Android.cpp +++ b/shell/android/jni/src/Android.cpp @@ -29,7 +29,7 @@ extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_JNIdc_rendinit(JNIEnv *env,jobject obj,jint w,jint h) __attribute__((visibility("default"))); JNIEXPORT void JNICALL Java_com_reicast_emulator_JNIdc_rendframe(JNIEnv *env,jobject obj) __attribute__((visibility("default"))); - JNIEXPORT void JNICALL Java_com_reicast_emulator_JNIdc_kcode(JNIEnv * env, jobject obj,u32 k_code, u32 l_t, u32 r_t, u32 jx, u32 jy) __attribute__((visibility("default"))); + JNIEXPORT void JNICALL Java_com_reicast_emulator_JNIdc_kcode(JNIEnv * env, jobject obj, jintArray k_code, jintArray l_t, jintArray r_t, jintArray jx, jintArray jy) __attribute__((visibility("default"))); JNIEXPORT void JNICALL Java_com_reicast_emulator_JNIdc_vjoy(JNIEnv * env, jobject obj,u32 id,float x, float y, float w, float h) __attribute__((visibility("default"))); //JNIEXPORT jint JNICALL Java_com_reicast_emulator_JNIdc_play(JNIEnv *env,jobject obj,jshortArray result,jint size); }; @@ -244,17 +244,37 @@ JNIEXPORT jint JNICALL Java_com_reicast_emulator_JNIdc_data(JNIEnv *env,jobject JNIEXPORT void JNICALL Java_com_reicast_emulator_JNIdc_rendframe(JNIEnv *env,jobject obj) { + /*char kcode_str0[100]; + char kcode_str1[100]; + sprintf(kcode_str0,"%d", kcode[0]); + sprintf(kcode_str1,"%d", kcode[1]); + __android_log_write(ANDROID_LOG_INFO, "kcode 0", kcode_str0); + __android_log_write(ANDROID_LOG_INFO, "kcode 1", kcode_str1);*/ while(!rend_single_frame()) ; } -JNIEXPORT void JNICALL Java_com_reicast_emulator_JNIdc_kcode(JNIEnv * env, jobject obj,u32 k_code, u32 l_t, u32 r_t, u32 jx, u32 jy) +JNIEXPORT void JNICALL Java_com_reicast_emulator_JNIdc_kcode(JNIEnv * env, jobject obj, jintArray k_code, jintArray l_t, jintArray r_t, jintArray jx, jintArray jy) { - lt[0] = l_t; - rt[0] = r_t; - kcode[0] = k_code; - kcode[3] = kcode[2] = kcode[1] = 0xFFFF; - joyx[0]=jx; - joyy[0]=jy; + jint *k_code_body = env->GetIntArrayElements(k_code, 0); + jint *l_t_body = env->GetIntArrayElements(l_t, 0); + jint *r_t_body = env->GetIntArrayElements(r_t, 0); + jint *jx_body = env->GetIntArrayElements(jx, 0); + jint *jy_body = env->GetIntArrayElements(jy, 0); + + for(int i = 0; i < 4; i++) + { + kcode[i] = k_code_body[i]; + lt[i] = l_t_body[i]; + rt[i] = r_t_body[i]; + joyx[i] = jx_body[i]; + joyy[i] = jy_body[i]; + } + + env->ReleaseIntArrayElements(k_code, k_code_body, 0); + env->ReleaseIntArrayElements(l_t, l_t_body, 0); + env->ReleaseIntArrayElements(r_t, r_t_body, 0); + env->ReleaseIntArrayElements(jx, jx_body, 0); + env->ReleaseIntArrayElements(jy, jy_body, 0); } JNIEXPORT void JNICALL Java_com_reicast_emulator_JNIdc_rendinit(JNIEnv * env, jobject obj, jint w,jint h) @@ -294,4 +314,4 @@ u32 os_Push(void* frame, u32 amt, bool wait) bool os_IsAudioBuffered() { return jenv->CallIntMethod(track,writemid,jsamples,-1)==0; -} \ No newline at end of file +} diff --git a/shell/android/src/com/reicast/emulator/GL2JNIActivity.java b/shell/android/src/com/reicast/emulator/GL2JNIActivity.java index 515db92ed..4792f2891 100644 --- a/shell/android/src/com/reicast/emulator/GL2JNIActivity.java +++ b/shell/android/src/com/reicast/emulator/GL2JNIActivity.java @@ -1,5 +1,9 @@ package com.reicast.emulator; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; + import tv.ouya.console.api.OuyaController; import android.annotation.TargetApi; import android.app.Activity; @@ -29,10 +33,12 @@ public class GL2JNIActivity extends Activity { PopupWindow popUp; LayoutParams params; MOGAInput moga = new MOGAInput(); - static boolean xbox = false, nVidia = false; - float globalLS_X, globalLS_Y, previousLS_X, previousLS_Y; + static boolean[] xbox = { false, false, false, false }, nVidia = { false, false, false, false }; + float[] globalLS_X = new float[4], globalLS_Y = new float[4], previousLS_X = new float[4], previousLS_Y = new float[4]; - int map[]; + HashMap deviceId_PlayerNum = new HashMap(); + + int map[][]; View addbut(int x, OnClickListener ocl) { ImageButton but = new ImageButton(this); @@ -111,6 +117,10 @@ public class GL2JNIActivity extends Activity { @Override protected void onCreate(Bundle icicle) { + map = new int[4][]; + deviceId_PlayerNum.put(87, 0); + deviceId_PlayerNum.put(86, 1); + requestWindowFeature(Window.FEATURE_NO_TITLE); moga.onCreate(this); @@ -129,24 +139,32 @@ public class GL2JNIActivity extends Activity { // Call parent onCreate() super.onCreate(icicle); + OuyaController.init(this); int joys[] = InputDevice.getDeviceIds(); for (int i = 0; i < joys.length; i++) { Log.d("reidc", "InputDevice ID: " + joys[i]); Log.d("reidc", "InputDevice Name: " + InputDevice.getDevice(joys[i]).getName()); + + Integer playerNum = deviceId_PlayerNum.get(joys[i]); + if (playerNum != null) { + if (InputDevice.getDevice(joys[i]).getName() .equals("Sony PLAYSTATION(R)3 Controller")) { - map = new int[] { + map[playerNum] = new int[] { OuyaController.BUTTON_Y, key_CONT_B, OuyaController.BUTTON_U, key_CONT_A, OuyaController.BUTTON_O, key_CONT_X, OuyaController.BUTTON_A, key_CONT_Y, - OuyaController.BUTTON_DPAD_UP, key_CONT_DPAD_UP, - OuyaController.BUTTON_DPAD_DOWN, key_CONT_DPAD_DOWN, - OuyaController.BUTTON_DPAD_LEFT, key_CONT_DPAD_LEFT, - OuyaController.BUTTON_DPAD_RIGHT, key_CONT_DPAD_RIGHT, + OuyaController.BUTTON_DPAD_UP, key_CONT_DPAD_UP, + OuyaController.BUTTON_DPAD_DOWN, + key_CONT_DPAD_DOWN, + OuyaController.BUTTON_DPAD_LEFT, + key_CONT_DPAD_LEFT, + OuyaController.BUTTON_DPAD_RIGHT, + key_CONT_DPAD_RIGHT, OuyaController.BUTTON_MENU, key_CONT_START, OuyaController.BUTTON_R1, key_CONT_START @@ -154,7 +172,7 @@ public class GL2JNIActivity extends Activity { }; } else if (InputDevice.getDevice(joys[i]).getName() .equals("Microsoft X-Box 360 pad")) { - map = new int[] { + map[playerNum] = new int[] { OuyaController.BUTTON_O, key_CONT_A, OuyaController.BUTTON_A, key_CONT_B, OuyaController.BUTTON_Y, key_CONT_Y, @@ -170,10 +188,10 @@ public class GL2JNIActivity extends Activity { OuyaController.BUTTON_MENU, key_CONT_START, OuyaController.BUTTON_R1, key_CONT_START }; - xbox = true; + xbox[playerNum] = true; } else if (InputDevice.getDevice(joys[i]).getName() .contains("NVIDIA Corporation NVIDIA Controller")) { - map = new int[] { + map[playerNum] = new int[] { OuyaController.BUTTON_O, key_CONT_A, OuyaController.BUTTON_A, key_CONT_B, OuyaController.BUTTON_Y, key_CONT_Y, @@ -189,9 +207,9 @@ public class GL2JNIActivity extends Activity { OuyaController.BUTTON_MENU, key_CONT_START, OuyaController.BUTTON_R1, key_CONT_START }; - nVidia = true; + nVidia[playerNum] = true; } else if (!moga.isActive) { // Ouya controller - map = new int[] { + map[playerNum] = new int[] { OuyaController.BUTTON_O, key_CONT_A, OuyaController.BUTTON_A, key_CONT_B, OuyaController.BUTTON_Y, key_CONT_Y, @@ -208,6 +226,7 @@ public class GL2JNIActivity extends Activity { OuyaController.BUTTON_MENU, key_CONT_START, OuyaController.BUTTON_R1, key_CONT_START }; } + } } // When viewing a resource, pass its URI to the native code for opening @@ -228,7 +247,12 @@ public class GL2JNIActivity extends Activity { // Log.w("INPUT", event.toString() + " " + event.getSource()); // Get all the axis for the KeyEvent - if (nVidia) { + Integer playerNum = deviceId_PlayerNum.get(event.getDeviceId()); + Log.w("onGenericMotionEvent playerNum", String.valueOf(playerNum)); + if (playerNum == null) + return false; + + if (nVidia[playerNum]) { JNIdc.hide_osd(); } @@ -245,23 +269,23 @@ public class GL2JNIActivity extends Activity { float L2 = event.getAxisValue(OuyaController.AXIS_L2); float R2 = event.getAxisValue(OuyaController.AXIS_R2); - if (xbox || nVidia) { - previousLS_X = globalLS_X; - previousLS_Y = globalLS_Y; - globalLS_X = LS_X; - globalLS_Y = LS_Y; + if (xbox[playerNum] || nVidia[playerNum]) { + previousLS_X[playerNum] = globalLS_X[playerNum]; + previousLS_Y[playerNum] = globalLS_Y[playerNum]; + globalLS_X[playerNum] = LS_X; + globalLS_Y[playerNum] = LS_Y; } - GL2JNIView.lt = (int) (L2 * 255); - GL2JNIView.rt = (int) (R2 * 255); + GL2JNIView.lt[playerNum] = (int) (L2 * 255); + GL2JNIView.rt[playerNum] = (int) (R2 * 255); - GL2JNIView.jx = (int) (LS_X * 126); - GL2JNIView.jy = (int) (LS_Y * 126); + GL2JNIView.jx[playerNum] = (int) (LS_X * 126); + GL2JNIView.jy[playerNum] = (int) (LS_Y * 126); } } - if ((xbox || nVidia) && globalLS_X == previousLS_X && globalLS_Y == previousLS_Y) + if ((xbox[playerNum] || nVidia[playerNum]) && globalLS_X[playerNum] == previousLS_X[playerNum] && globalLS_Y[playerNum] == previousLS_Y[playerNum]) // Only handle Left Stick on an Xbox 360 controller if there was some actual motion on the stick, // so otherwise the event can be handled as a DPAD event return false; @@ -313,16 +337,19 @@ public class GL2JNIActivity extends Activity { * }; */ - boolean handle_key(int kc, boolean down) { + boolean handle_key(Integer playerNum, int kc, boolean down) { + if (playerNum == null) + return false; + if (!moga.isActive) { boolean rav = false; - for (int i = 0; i < map.length; i += 2) { - if (map[i + 0] == kc) { + for (int i = 0; i < map[playerNum].length; i += 2) { + if (map[playerNum][i + 0] == kc) { if (down) - GL2JNIView.kcode_raw &= ~map[i + 1]; + GL2JNIView.kcode_raw[playerNum] &= ~map[playerNum][i + 1]; else - GL2JNIView.kcode_raw |= map[i + 1]; + GL2JNIView.kcode_raw[playerNum] |= map[playerNum][i + 1]; rav = true; break; @@ -337,11 +364,17 @@ public class GL2JNIActivity extends Activity { } public boolean onKeyUp(int keyCode, KeyEvent event) { - return handle_key(keyCode, false) || super.onKeyUp(keyCode, event); + Integer playerNum = deviceId_PlayerNum.get(event.getDeviceId()); + Log.w("onKeyUp playerNum", String.valueOf(playerNum)); + + return handle_key(playerNum, keyCode, false) || super.onKeyUp(keyCode, event); } public boolean onKeyDown(int keyCode, KeyEvent event) { - if (handle_key(keyCode, true)) { + Integer playerNum = deviceId_PlayerNum.get(event.getDeviceId()); + Log.w("onKeyDown playerNum", String.valueOf(playerNum)); + + if (handle_key(playerNum, keyCode, true)) { JNIdc.hide_osd(); return true; } diff --git a/shell/android/src/com/reicast/emulator/GL2JNIView.java b/shell/android/src/com/reicast/emulator/GL2JNIView.java index b9a75cc63..0098e5d5f 100644 --- a/shell/android/src/com/reicast/emulator/GL2JNIView.java +++ b/shell/android/src/com/reicast/emulator/GL2JNIView.java @@ -120,7 +120,9 @@ class GL2JNIView extends GLSurfaceView JNIdc.data(1, GL2JNIActivity.syms); JNIdc.hide_osd(); - JNIdc.kcode(0xFFFF,0,0,128,128); + int[] kcode = { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF }; + int[] rt = { 0, 0, 0, 0 }, lt = { 0, 0, 0, 0 }; + int[] jx = { 128, 128, 128, 128 }, jy = { 128, 128, 128, 128 }; JNIdc.init(fileName); @@ -264,8 +266,8 @@ class GL2JNIView extends GLSurfaceView } */ - static int kcode_raw = 0xFFFF; - static int lt, rt, jx, jy; + static int[] kcode_raw = { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF }; + static int[] lt = new int[4], rt = new int[4], jx = new int[4], jy = new int[4]; @Override public boolean onTouchEvent(final MotionEvent event) { @@ -321,8 +323,8 @@ class GL2JNIView extends GLSurfaceView anal_id=event.getPointerId(i); } else if (vjoy[j][4]==-4) ; - else if(vjoy[j][4]==-1) lt=pre; - else if(vjoy[j][4]==-2) rt=pre; + else if(vjoy[j][4]==-1) lt[0]=pre; + else if(vjoy[j][4]==-2) rt[0]=pre; else rv&=~(int)vjoy[j][4]; } @@ -365,8 +367,8 @@ class GL2JNIView extends GLSurfaceView reset_analog(); anal_id=-1; rv=0xFFFF; - rt=0; - lt=0; + rt[0]=0; + lt[0]=0; for(int j=0;j entry : mMotions.entrySet()) From 53a89c7ce2e9938d82cbba858e8cc93f3795f886 Mon Sep 17 00:00:00 2001 From: LoungeKatt Date: Sun, 5 Jan 2014 18:10:27 -0500 Subject: [PATCH 2/5] Add an ignore for orig files to prevent saved merge backups --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 1d1690462..e4350c09b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .DS_Store *.class +*.orig bin/ gen/ From 3cb8b2cc6ebc275d87f5c7224c02db03a60310a4 Mon Sep 17 00:00:00 2001 From: Matteo Hausner Date: Sat, 4 Jan 2014 20:08:32 +0100 Subject: [PATCH 3/5] Added configuration GUI for physical controllers Reverted changes in maple_cfg.cpp except a minor memory leak Fixed an issue with the Xbox 360 controller support, that the first press of the DPAD would not get handled Lots of improvments on multi-controller support --- core/hw/maple/maple_cfg.cpp | 1 - shell/android/jni/src/Android.cpp | 27 +- .../res/layout/controllers_fragment.xml | 151 ++++++++++ shell/android/res/values/strings.xml | 15 +- .../reicast/emulator/ControllersFragment.java | 268 ++++++++++++++++++ .../com/reicast/emulator/GL2JNIActivity.java | 76 ++++- .../src/com/reicast/emulator/JNIdc.java | 2 + .../com/reicast/emulator/MainActivity.java | 18 +- 8 files changed, 534 insertions(+), 24 deletions(-) create mode 100644 shell/android/res/layout/controllers_fragment.xml create mode 100644 shell/android/src/com/reicast/emulator/ControllersFragment.java diff --git a/core/hw/maple/maple_cfg.cpp b/core/hw/maple/maple_cfg.cpp index 7757a5217..16e5a63fe 100644 --- a/core/hw/maple/maple_cfg.cpp +++ b/core/hw/maple/maple_cfg.cpp @@ -69,7 +69,6 @@ void mcfg_Create(MapleDeviceType type,u32 bus,u32 port) void mcfg_CreateDevices() { mcfg_Create(MDT_SegaController,0,5); - mcfg_Create(MDT_SegaController,1,5); #ifdef HAS_VMU mcfg_Create(MDT_SegaVMU,0,0); diff --git a/shell/android/jni/src/Android.cpp b/shell/android/jni/src/Android.cpp index f322c0d47..3abaff8b8 100644 --- a/shell/android/jni/src/Android.cpp +++ b/shell/android/jni/src/Android.cpp @@ -13,6 +13,7 @@ #include "profiler/profiler.h" #include "cfg/cfg.h" #include "rend/TexCache.h" +#include "hw/maple/maple_devs.h" #include "util.h" @@ -32,6 +33,8 @@ extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_JNIdc_kcode(JNIEnv * env, jobject obj, jintArray k_code, jintArray l_t, jintArray r_t, jintArray jx, jintArray jy) __attribute__((visibility("default"))); JNIEXPORT void JNICALL Java_com_reicast_emulator_JNIdc_vjoy(JNIEnv * env, jobject obj,u32 id,float x, float y, float w, float h) __attribute__((visibility("default"))); //JNIEXPORT jint JNICALL Java_com_reicast_emulator_JNIdc_play(JNIEnv *env,jobject obj,jshortArray result,jint size); + + JNIEXPORT void JNICALL Java_com_reicast_emulator_JNIdc_initControllers(JNIEnv *env, jobject obj, jbooleanArray controllers) __attribute__((visibility("default"))); }; void egl_stealcntx(); @@ -39,6 +42,7 @@ void SetApplicationPath(wchar *path); int dc_init(int argc,wchar* argv[]); void dc_run(); void dc_term(); +void mcfg_Create(MapleDeviceType type,u32 bus,u32 port); bool VramLockedWrite(u8* address); @@ -51,6 +55,9 @@ extern int screen_width,screen_height; static u64 tvs_base; static char CurFileName[256]; +// Additonal controllers 2, 3 and 4 connected ? +static bool add_controllers[3] = { false, true, false }; + u16 kcode[4]; u32 vks[4]; s8 joyx[4],joyy[4]; @@ -84,6 +91,13 @@ static void *ThreadHandler(void *UserData) strcat(Args[2],P); } + // Add additonal controllers + for (int i = 0; i < 3; i++) + { + if (add_controllers[i]) + mcfg_Create(MDT_SegaController,i+1,5); + } + // Run nullDC emulator dc_init(Args[2]? 3:1,Args); } @@ -244,12 +258,6 @@ JNIEXPORT jint JNICALL Java_com_reicast_emulator_JNIdc_data(JNIEnv *env,jobject JNIEXPORT void JNICALL Java_com_reicast_emulator_JNIdc_rendframe(JNIEnv *env,jobject obj) { - /*char kcode_str0[100]; - char kcode_str1[100]; - sprintf(kcode_str0,"%d", kcode[0]); - sprintf(kcode_str1,"%d", kcode[1]); - __android_log_write(ANDROID_LOG_INFO, "kcode 0", kcode_str0); - __android_log_write(ANDROID_LOG_INFO, "kcode 1", kcode_str1);*/ while(!rend_single_frame()) ; } @@ -303,6 +311,13 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_JNIdc_vjoy(JNIEnv * env, jobjec } } +JNIEXPORT void JNICALL Java_com_reicast_emulator_JNIdc_initControllers(JNIEnv *env, jobject obj, jbooleanArray controllers) +{ + jboolean *controllers_body = env->GetBooleanArrayElements(controllers, 0); + memcpy(add_controllers, controllers_body, 3); + env->ReleaseBooleanArrayElements(controllers, controllers_body, 0); +} + u32 os_Push(void* frame, u32 amt, bool wait) { verify(amt==SAMPLE_COUNT); diff --git a/shell/android/res/layout/controllers_fragment.xml b/shell/android/res/layout/controllers_fragment.xml new file mode 100644 index 000000000..d5a8c5c60 --- /dev/null +++ b/shell/android/res/layout/controllers_fragment.xml @@ -0,0 +1,151 @@ + + + + + + + + + +