mirror of
https://github.com/DrBeef/JKXR.git
synced 2024-11-10 14:52:00 +00:00
Support for external haptics providers
This commit is contained in:
parent
077cfe159e
commit
7b410f5867
8 changed files with 310 additions and 32 deletions
|
@ -48,6 +48,7 @@ android {
|
|||
dependencies {
|
||||
implementation "com.android.support:support-compat:26.1.0"
|
||||
implementation "com.android.support:support-core-utils:26.1.0"
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
|
||||
}
|
||||
|
||||
repositories {
|
||||
|
|
|
@ -1661,6 +1661,59 @@ void JKVR_processHaptics() {
|
|||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
void jni_haptic_event(const char *event, int position, int flags, int intensity, float angle,
|
||||
float yHeight);
|
||||
void jni_haptic_updateevent(const char *event, int intensity, float angle);
|
||||
void jni_haptic_stopevent(const char *event);
|
||||
void jni_haptic_endframe();
|
||||
void jni_haptic_enable();
|
||||
void jni_haptic_disable();
|
||||
};
|
||||
|
||||
void JKVR_ExternalHapticEvent(const char* event, int position, int flags, int intensity, float angle, float yHeight )
|
||||
{
|
||||
jni_haptic_event(event, position, flags, intensity, angle, yHeight);
|
||||
}
|
||||
|
||||
void JKVR_HapticUpdateEvent(const char* event, int intensity, float angle )
|
||||
{
|
||||
jni_haptic_updateevent(event, intensity, angle);
|
||||
}
|
||||
|
||||
void JKVR_HapticEndFrame()
|
||||
{
|
||||
jni_haptic_endframe();
|
||||
}
|
||||
|
||||
void JKVR_HapticStopEvent(const char* event)
|
||||
{
|
||||
jni_haptic_stopevent(event);
|
||||
}
|
||||
|
||||
void JKVR_HapticEnable()
|
||||
{
|
||||
static bool firstTime = true;
|
||||
if (firstTime) {
|
||||
jni_haptic_enable();
|
||||
firstTime = false;
|
||||
jni_haptic_event("fire_pistol", 0, 0, 100, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void JKVR_HapticDisable()
|
||||
{
|
||||
jni_haptic_disable();
|
||||
}
|
||||
|
||||
/*
|
||||
* event - name of event
|
||||
* position - for the use of external haptics providers to indicate which bit of haptic hardware should be triggered
|
||||
* flags - a way for the code to specify which controller to produce haptics on, if 0 then weaponFireChannel is calculated in this function
|
||||
* intensity - 0-100
|
||||
* angle - yaw angle (again for external haptics devices) to place the feedback correctly
|
||||
* yHeight - for external haptics devices to place the feedback correctly
|
||||
*/
|
||||
void JKVR_HapticEvent(const char* event, int position, int flags, int intensity, float angle, float yHeight )
|
||||
{
|
||||
if (vr_haptic_intensity->value == 0.0f)
|
||||
|
@ -1668,9 +1721,8 @@ void JKVR_HapticEvent(const char* event, int position, int flags, int intensity,
|
|||
return;
|
||||
}
|
||||
|
||||
// engine_t* engine = VR_GetEngine();
|
||||
// jstring StringArg1 = (*(engine->java.Env))->NewStringUTF(engine->java.Env, event);
|
||||
// (*(engine->java.Env))->CallVoidMethod(engine->java.Env, engine->java.ActivityObject, android_haptic_event, StringArg1, position, flags, (int)(intensity * vr_hapticIntensity->value), angle, yHeight);
|
||||
//Pass on to any external services
|
||||
JKVR_ExternalHapticEvent(event, position, flags, intensity, angle, yHeight);
|
||||
|
||||
//Controller Haptic Support
|
||||
int weaponFireChannel = vr.weapon_stabilised ? 3 : (vr_control_scheme->integer ? 2 : 1);
|
||||
|
@ -1977,6 +2029,94 @@ void jni_shutdown()
|
|||
return env->CallVoidMethod(jniCallbackObj, android_shutdown);
|
||||
}
|
||||
|
||||
jmethodID android_haptic_event;
|
||||
jmethodID android_haptic_updateevent;
|
||||
jmethodID android_haptic_stopevent;
|
||||
jmethodID android_haptic_endframe;
|
||||
jmethodID android_haptic_enable;
|
||||
jmethodID android_haptic_disable;
|
||||
|
||||
void jni_haptic_event(const char* event, int position, int flags, int intensity, float angle, float yHeight)
|
||||
{
|
||||
JNIEnv *env;
|
||||
jobject tmp;
|
||||
if ((jVM->GetEnv((void**) &env, JNI_VERSION_1_4))<0)
|
||||
{
|
||||
jVM->AttachCurrentThread(&env, NULL);
|
||||
}
|
||||
|
||||
jstring StringArg1 = env->NewStringUTF(event);
|
||||
|
||||
return env->CallVoidMethod(jniCallbackObj, android_haptic_event, StringArg1, position, flags, intensity, angle, yHeight);
|
||||
}
|
||||
|
||||
void jni_haptic_updateevent(const char* event, int intensity, float angle)
|
||||
{
|
||||
JNIEnv *env;
|
||||
jobject tmp;
|
||||
if ((jVM->GetEnv((void**) &env, JNI_VERSION_1_4))<0)
|
||||
{
|
||||
jVM->AttachCurrentThread(&env, NULL);
|
||||
}
|
||||
|
||||
jstring StringArg1 = env->NewStringUTF(event);
|
||||
|
||||
return env->CallVoidMethod(jniCallbackObj, android_haptic_updateevent, StringArg1, intensity, angle);
|
||||
}
|
||||
|
||||
void jni_haptic_stopevent(const char* event)
|
||||
{
|
||||
ALOGV("Calling: jni_haptic_stopevent");
|
||||
JNIEnv *env;
|
||||
jobject tmp;
|
||||
if ((jVM->GetEnv((void**) &env, JNI_VERSION_1_4))<0)
|
||||
{
|
||||
jVM->AttachCurrentThread(&env, NULL);
|
||||
}
|
||||
|
||||
jstring StringArg1 = env->NewStringUTF(event);
|
||||
|
||||
return env->CallVoidMethod(jniCallbackObj, android_haptic_stopevent, StringArg1);
|
||||
}
|
||||
|
||||
void jni_haptic_endframe()
|
||||
{
|
||||
JNIEnv *env;
|
||||
jobject tmp;
|
||||
if ((jVM->GetEnv((void**) &env, JNI_VERSION_1_4))<0)
|
||||
{
|
||||
jVM->AttachCurrentThread(&env, NULL);
|
||||
}
|
||||
|
||||
return env->CallVoidMethod(jniCallbackObj, android_haptic_endframe);
|
||||
}
|
||||
|
||||
void jni_haptic_enable()
|
||||
{
|
||||
ALOGV("Calling: jni_haptic_enable");
|
||||
JNIEnv *env;
|
||||
jobject tmp;
|
||||
if ((jVM->GetEnv((void**) &env, JNI_VERSION_1_4))<0)
|
||||
{
|
||||
jVM->AttachCurrentThread(&env, NULL);
|
||||
}
|
||||
|
||||
return env->CallVoidMethod(jniCallbackObj, android_haptic_enable);
|
||||
}
|
||||
|
||||
void jni_haptic_disable()
|
||||
{
|
||||
ALOGV("Calling: jni_haptic_disable");
|
||||
JNIEnv *env;
|
||||
jobject tmp;
|
||||
if ((jVM->GetEnv((void**) &env, JNI_VERSION_1_4))<0)
|
||||
{
|
||||
jVM->AttachCurrentThread(&env, NULL);
|
||||
}
|
||||
|
||||
return env->CallVoidMethod(jniCallbackObj, android_haptic_disable);
|
||||
}
|
||||
|
||||
int JNI_OnLoad(JavaVM* vm, void* reserved)
|
||||
{
|
||||
JNIEnv *env;
|
||||
|
@ -2074,6 +2214,12 @@ JNIEXPORT void JNICALL Java_com_drbeef_jkquest_GLES3JNILib_onStart( JNIEnv * env
|
|||
jclass callbackClass = env->GetObjectClass( jniCallbackObj);
|
||||
|
||||
android_shutdown = env->GetMethodID(callbackClass,"shutdown","()V");
|
||||
android_haptic_event = env->GetMethodID(callbackClass, "haptic_event", "(Ljava/lang/String;IIIFF)V");
|
||||
android_haptic_updateevent = env->GetMethodID(callbackClass, "haptic_updateevent", "(Ljava/lang/String;IF)V");
|
||||
android_haptic_stopevent = env->GetMethodID(callbackClass, "haptic_stopevent", "(Ljava/lang/String;)V");
|
||||
android_haptic_endframe = env->GetMethodID(callbackClass, "haptic_endframe", "()V");
|
||||
android_haptic_enable = env->GetMethodID(callbackClass, "haptic_enable", "()V");
|
||||
android_haptic_disable = env->GetMethodID(callbackClass, "haptic_disable", "()V");
|
||||
|
||||
ovrAppThread * appThread = (ovrAppThread *)((size_t)handle);
|
||||
ovrMessage message;
|
||||
|
|
|
@ -841,9 +841,6 @@ void CL_Frame ( int msec,float fractionMsec ) {
|
|||
|
||||
JKVR_processHaptics();
|
||||
|
||||
//trigger frame tick for haptics
|
||||
JKVR_HapticEvent("frame_tick", 0, 0, 0, 0, 0);
|
||||
|
||||
// see if we need to update any userinfo
|
||||
CL_CheckUserinfo();
|
||||
|
||||
|
@ -894,6 +891,8 @@ void CL_Frame ( int msec,float fractionMsec ) {
|
|||
|
||||
Con_RunConsole();
|
||||
|
||||
JKVR_HapticEndFrame();
|
||||
|
||||
cls.framecount++;
|
||||
}
|
||||
|
||||
|
|
|
@ -4792,7 +4792,9 @@ Ghoul2 Insert End
|
|||
{
|
||||
cvar_t *vr_saber_block_debounce_time = gi.cvar("vr_saber_block_debounce_time", "200", CVAR_ARCHIVE); // defined in VrCvars.h
|
||||
vr->saberBlockDebounce = cg.time + vr_saber_block_debounce_time->integer;
|
||||
}
|
||||
|
||||
cgi_HapticEvent("shotgun_fire", 0, 0, 100, 0, 0);
|
||||
}
|
||||
|
||||
if (CG_getPlayer1stPersonSaber(cent) &&
|
||||
cent->gent->client->ps.saberLockEnemy != ENTITYNUM_NONE)
|
||||
|
|
|
@ -2004,6 +2004,12 @@ wasForceSpeed=isForceSpeed;
|
|||
cgi_CM_SnapPVS( cg.refdef.vieworg, cg.snap->areamask );
|
||||
}
|
||||
|
||||
if (cg.predicted_player_state.stats[STAT_HEALTH] > 0 &&
|
||||
cg.predicted_player_state.stats[STAT_HEALTH] < 40)
|
||||
{
|
||||
cgi_HapticEvent("heartbeat", 0, 0, cg.predicted_player_state.stats[STAT_HEALTH], 0, 0);
|
||||
}
|
||||
|
||||
if (vr->item_selector)
|
||||
{
|
||||
CG_DrawItemSelector();
|
||||
|
|
|
@ -3241,7 +3241,7 @@ void CG_FireWeapon( centity_t *cent, qboolean alt_fire )
|
|||
//Haptics
|
||||
switch (ent->weapon) {
|
||||
case WP_SABER:
|
||||
cgi_HapticEvent("chainsaw_fire", position, 0, 50, 0, 0);
|
||||
cgi_HapticEvent("chainsaw_fire", position, 0, 40, 0, 0);
|
||||
break;
|
||||
case WP_BRYAR_PISTOL:
|
||||
case WP_BOWCASTER:
|
||||
|
|
BIN
Projects/Android/libs/haptic_service.aar
Normal file
BIN
Projects/Android/libs/haptic_service.aar
Normal file
Binary file not shown.
|
@ -2,6 +2,27 @@
|
|||
package com.drbeef.jkquest;
|
||||
|
||||
|
||||
import static android.system.Os.setenv;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.AssetManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.drbeef.externalhapticsservice.HapticServiceClient;
|
||||
import com.drbeef.externalhapticsservice.HapticsConstants;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
|
@ -10,35 +31,14 @@ import java.io.FileReader;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.AssetManager;
|
||||
|
||||
import android.media.AudioRecord;
|
||||
import android.media.AudioTrack;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
|
||||
import static android.system.Os.setenv;
|
||||
import java.util.Vector;
|
||||
|
||||
@SuppressLint("SdCardPath") public class GLES3JNIActivity extends Activity implements SurfaceHolder.Callback
|
||||
{
|
||||
private static String game = "";
|
||||
|
||||
private boolean hapticsEnabled = false;
|
||||
|
||||
// Load the gles3jni library right away to make sure JNI_OnLoad() gets called as the very first thing.
|
||||
static
|
||||
{
|
||||
|
@ -85,11 +85,21 @@ import static android.system.Os.setenv;
|
|||
// Main components
|
||||
protected static GLES3JNIActivity mSingleton;
|
||||
|
||||
private Vector<HapticServiceClient> externalHapticsServiceClients = new Vector<>();
|
||||
|
||||
//Use a vector of pairs, it is possible a given package _could_ in the future support more than one haptic service
|
||||
//so a map here of Package -> Action would not work.
|
||||
private static Vector<Pair<String, String>> externalHapticsServiceDetails = new Vector<>();
|
||||
|
||||
|
||||
public static void initialize() {
|
||||
// The static nature of the singleton and Android quirkyness force us to initialize everything here
|
||||
// Otherwise, when exiting the app and returning to it, these variables *keep* their pre exit values
|
||||
mSingleton = null;
|
||||
|
||||
//Add possible external haptic service details here
|
||||
externalHapticsServiceDetails.add(Pair.create(HapticsConstants.BHAPTICS_PACKAGE, HapticsConstants.BHAPTICS_ACTION_FILTER));
|
||||
externalHapticsServiceDetails.add(Pair.create(HapticsConstants.FORCETUBE_PACKAGE, HapticsConstants.FORCETUBE_ACTION_FILTER));
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
|
@ -235,6 +245,16 @@ import static android.system.Os.setenv;
|
|||
|
||||
}
|
||||
|
||||
for (Pair<String, String> serviceDetail : externalHapticsServiceDetails) {
|
||||
HapticServiceClient client = new HapticServiceClient(this, (state, desc) -> {
|
||||
Log.v(APPLICATION, "ExternalHapticsService " + serviceDetail.second + ": " + desc);
|
||||
}, new Intent(serviceDetail.second)
|
||||
.setPackage(serviceDetail.first));
|
||||
|
||||
client.bindService();
|
||||
externalHapticsServiceClients.add(client);
|
||||
}
|
||||
|
||||
mNativeHandle = GLES3JNILib.onCreate( this, commandLineParams );
|
||||
}
|
||||
|
||||
|
@ -371,4 +391,108 @@ import static android.system.Os.setenv;
|
|||
mSurfaceHolder = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void haptic_event(String event, int position, int flags, int intensity, float angle, float yHeight) {
|
||||
|
||||
boolean areHapticsEnabled = hapticsEnabled;
|
||||
for (HapticServiceClient externalHapticsServiceClient : externalHapticsServiceClients) {
|
||||
|
||||
if (externalHapticsServiceClient.hasService()) {
|
||||
try {
|
||||
//Enabled all haptics services if required
|
||||
if (!areHapticsEnabled)
|
||||
{
|
||||
externalHapticsServiceClient.getHapticsService().hapticEnable();
|
||||
hapticsEnabled = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
//Uses the Doom3Quest and RTCWQuest haptic patterns
|
||||
String app = "Doom3Quest";
|
||||
String eventID = event;
|
||||
if (event.contains(":"))
|
||||
{
|
||||
String[] items = event.split(":");
|
||||
app = items[0];
|
||||
eventID = items[1];
|
||||
}
|
||||
externalHapticsServiceClient.getHapticsService().hapticEvent(app, eventID, position, flags, intensity, angle, yHeight);
|
||||
}
|
||||
catch (RemoteException r)
|
||||
{
|
||||
Log.v(TAG, r.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void haptic_updateevent(String event, int intensity, float angle) {
|
||||
|
||||
for (HapticServiceClient externalHapticsServiceClient : externalHapticsServiceClients) {
|
||||
|
||||
if (externalHapticsServiceClient.hasService()) {
|
||||
try {
|
||||
externalHapticsServiceClient.getHapticsService().hapticUpdateEvent(APPLICATION, event, intensity, angle);
|
||||
} catch (RemoteException r) {
|
||||
Log.v(APPLICATION, r.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void haptic_stopevent(String event) {
|
||||
|
||||
for (HapticServiceClient externalHapticsServiceClient : externalHapticsServiceClients) {
|
||||
|
||||
if (externalHapticsServiceClient.hasService()) {
|
||||
try {
|
||||
externalHapticsServiceClient.getHapticsService().hapticStopEvent(APPLICATION, event);
|
||||
} catch (RemoteException r) {
|
||||
Log.v(APPLICATION, r.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void haptic_endframe() {
|
||||
|
||||
for (HapticServiceClient externalHapticsServiceClient : externalHapticsServiceClients) {
|
||||
|
||||
if (externalHapticsServiceClient.hasService()) {
|
||||
try {
|
||||
externalHapticsServiceClient.getHapticsService().hapticFrameTick();
|
||||
} catch (RemoteException r) {
|
||||
Log.v(APPLICATION, r.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void haptic_enable() {
|
||||
|
||||
for (HapticServiceClient externalHapticsServiceClient : externalHapticsServiceClients) {
|
||||
|
||||
if (externalHapticsServiceClient.hasService()) {
|
||||
try {
|
||||
externalHapticsServiceClient.getHapticsService().hapticEnable();
|
||||
} catch (RemoteException r) {
|
||||
Log.v(APPLICATION, r.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void haptic_disable() {
|
||||
|
||||
for (HapticServiceClient externalHapticsServiceClient : externalHapticsServiceClients) {
|
||||
|
||||
if (externalHapticsServiceClient.hasService()) {
|
||||
try {
|
||||
externalHapticsServiceClient.getHapticsService().hapticDisable();
|
||||
} catch (RemoteException r) {
|
||||
Log.v(APPLICATION, r.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue