From 2923bdc996aea9c6183873a5be3f1b186abc389a Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 25 Mar 2021 22:25:46 +0000 Subject: [PATCH] Support for looping patterns with rotation - Steam jets can be directional now - Added couple of missing haptics files - Adjusted Pistol/Shotgun and Chainsaw patterns --- .../jni/Doom3Quest/Doom3Quest_SurfaceView.c | 166 +++++++++++++++++- .../neo/game/Entity.cpp | 13 +- .../neo/game/Player.cpp | 19 +- .../neo/sound/snd_world.cpp | 27 +++ .../Weapon/Vest/Body_BFG9000_Init.tact | 1 + assets/bHaptics/Weapon/Vest/Body_Reload.tact | 1 + .../drbeef/doom3quest/GLES3JNIActivity.java | 166 ++++++++++-------- .../drbeef/doom3quest/bhaptics/bHaptics.java | 117 +++++++++--- 8 files changed, 396 insertions(+), 114 deletions(-) create mode 100644 assets/bHaptics/Weapon/Vest/Body_BFG9000_Init.tact create mode 100644 assets/bHaptics/Weapon/Vest/Body_Reload.tact diff --git a/Projects/Android/jni/Doom3Quest/Doom3Quest_SurfaceView.c b/Projects/Android/jni/Doom3Quest/Doom3Quest_SurfaceView.c index 4eb0a11..4782161 100644 --- a/Projects/Android/jni/Doom3Quest/Doom3Quest_SurfaceView.c +++ b/Projects/Android/jni/Doom3Quest/Doom3Quest_SurfaceView.c @@ -93,6 +93,7 @@ vrClientInfo vr; vrClientInfo *pVRClientInfo; jclass clazz; +static jobject d3questCallbackObj=0; float radians(float deg) { return (deg * M_PI) / 180.0; @@ -954,6 +955,49 @@ void Doom3Quest_Vibrate(int channel, float low, float high) vibration_channel_intensity[channel][1] = high; } +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_beginframe(); +void jni_haptic_endframe(); +void jni_haptic_enable(); +void jni_haptic_disable(); + +void Doom3Quest_HapticEvent(const char* event, int position, int flags, int intensity, float angle, float yHeight ) +{ + jni_haptic_event(event, position, flags, intensity, angle, yHeight); +} + +void Doom3Quest_HapticUpdateEvent(const char* event, int intensity, float angle ) +{ + jni_haptic_updateevent(event, intensity, angle); +} + +void Doom3Quest_HapticBeginFrame() +{ + jni_haptic_beginframe(); +} + +void Doom3Quest_HapticEndFrame() +{ + jni_haptic_endframe(); +} + +void Doom3Quest_HapticStopEvent(const char* event) +{ + jni_haptic_stopevent(event); +} + +void Doom3Quest_HapticEnable() +{ + jni_haptic_enable(); +} + +void Doom3Quest_HapticDisable() +{ + jni_haptic_disable(); +} + void VR_Doom3Main(int argc, char** argv); void VR_GetMove( float *joy_forward, float *joy_side, float *hmd_forward, float *hmd_side, float *up, float *yaw, float *pitch, float *roll ) { @@ -1486,7 +1530,6 @@ void shutdownVR() { ovrRenderer_Destroy( &gAppState.Renderer ); ovrEgl_DestroyContext( &gAppState.Egl ); (*java.Vm)->DetachCurrentThread( java.Vm ); - vrapi_Shutdown(); } void showLoadingIcon(); @@ -1580,7 +1623,7 @@ void * AppThreadFunction(void * parm ) { questType = 2; if (SS_MULTIPLIER == -1.0f) { - SS_MULTIPLIER = 1.1f; + SS_MULTIPLIER = 1.2f; } if (NUM_MULTI_SAMPLES == -1) @@ -1699,6 +1742,8 @@ void Doom3Quest_processHaptics() {//Handle haptics else vrapi_SetHapticVibrationSimple(gAppState.Ovr, controllerIDs[1 - h], 0.0f); } + + Doom3Quest_HapticBeginFrame(); } void showLoadingIcon() @@ -1881,6 +1926,8 @@ void Doom3Quest_submitFrame() gAppState.RenderThreadFrameIndex++; SDL_UnlockMutex(gAppState.RenderThreadFrameIndex_Mutex); } + + Doom3Quest_HapticEndFrame(); } @@ -1917,8 +1964,15 @@ Activity lifecycle */ jmethodID android_shutdown; +jmethodID android_haptic_event; +jmethodID android_haptic_updateevent; +jmethodID android_haptic_stopevent; +jmethodID android_haptic_beginframe; +jmethodID android_haptic_endframe; +jmethodID android_haptic_enable; +jmethodID android_haptic_disable; static JavaVM *jVM; -static jobject shutdownCallbackObj=0; +static jobject jniCallbackObj=0; void jni_shutdown() { @@ -1929,7 +1983,100 @@ void jni_shutdown() { (*jVM)->AttachCurrentThread(jVM,&env, NULL); } - return (*env)->CallVoidMethod(env, shutdownCallbackObj, android_shutdown); + return (*env)->CallVoidMethod(env, jniCallbackObj, android_shutdown); +} + +void jni_haptic_event(const char* event, int position, int flags, int intensity, float angle, float yHeight) +{ + JNIEnv *env; + jobject tmp; + if (((*jVM)->GetEnv(jVM, (void**) &env, JNI_VERSION_1_4))<0) + { + (*jVM)->AttachCurrentThread(jVM,&env, NULL); + } + + jstring StringArg1 = (*env)->NewStringUTF(env, event); + + return (*env)->CallVoidMethod(env, 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(jVM, (void**) &env, JNI_VERSION_1_4))<0) + { + (*jVM)->AttachCurrentThread(jVM,&env, NULL); + } + + jstring StringArg1 = (*env)->NewStringUTF(env, event); + + return (*env)->CallVoidMethod(env, 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(jVM, (void**) &env, JNI_VERSION_1_4))<0) + { + (*jVM)->AttachCurrentThread(jVM,&env, NULL); + } + + jstring StringArg1 = (*env)->NewStringUTF(env, event); + + return (*env)->CallVoidMethod(env, jniCallbackObj, android_haptic_stopevent, StringArg1); +} + +void jni_haptic_beginframe() +{ + JNIEnv *env; + jobject tmp; + if (((*jVM)->GetEnv(jVM, (void**) &env, JNI_VERSION_1_4))<0) + { + (*jVM)->AttachCurrentThread(jVM,&env, NULL); + } + + return (*env)->CallVoidMethod(env, jniCallbackObj, android_haptic_beginframe); +} + +void jni_haptic_endframe() +{ + JNIEnv *env; + jobject tmp; + if (((*jVM)->GetEnv(jVM, (void**) &env, JNI_VERSION_1_4))<0) + { + (*jVM)->AttachCurrentThread(jVM,&env, NULL); + } + + return (*env)->CallVoidMethod(env, jniCallbackObj, android_haptic_endframe); +} + +void jni_haptic_enable() +{ + ALOGV("Calling: jni_haptic_enable"); + JNIEnv *env; + jobject tmp; + if (((*jVM)->GetEnv(jVM, (void**) &env, JNI_VERSION_1_4))<0) + { + (*jVM)->AttachCurrentThread(jVM,&env, NULL); + } + + return (*env)->CallVoidMethod(env, jniCallbackObj, android_haptic_enable); +} + +void jni_haptic_disable() +{ + ALOGV("Calling: jni_haptic_disable"); + JNIEnv *env; + jobject tmp; + if (((*jVM)->GetEnv(jVM, (void**) &env, JNI_VERSION_1_4))<0) + { + (*jVM)->AttachCurrentThread(jVM,&env, NULL); + } + + return (*env)->CallVoidMethod(env, jniCallbackObj, android_haptic_disable); } JNIEXPORT jint JNICALL SDL_JNI_OnLoad(JavaVM* vm, void* reserved); @@ -2001,10 +2148,17 @@ JNIEXPORT void JNICALL Java_com_drbeef_doom3quest_GLES3JNILib_onStart( JNIEnv * { ALOGV( " GLES3JNILib::onStart()" ); - shutdownCallbackObj = (jobject)(*env)->NewGlobalRef(env, obj1); - jclass callbackClass = (*env)->GetObjectClass(env, shutdownCallbackObj); + jniCallbackObj = (jobject)(*env)->NewGlobalRef(env, obj1); + jclass callbackClass = (*env)->GetObjectClass(env, jniCallbackObj); android_shutdown = (*env)->GetMethodID(env,callbackClass,"shutdown","()V"); + android_haptic_event = (*env)->GetMethodID(env, callbackClass, "haptic_event", "(Ljava/lang/String;IIIFF)V"); + android_haptic_updateevent = (*env)->GetMethodID(env, callbackClass, "haptic_updateevent", "(Ljava/lang/String;IF)V"); + android_haptic_stopevent = (*env)->GetMethodID(env, callbackClass, "haptic_stopevent", "(Ljava/lang/String;)V"); + android_haptic_beginframe = (*env)->GetMethodID(env, callbackClass, "haptic_beginframe", "()V"); + android_haptic_endframe = (*env)->GetMethodID(env, callbackClass, "haptic_endframe", "()V"); + android_haptic_enable = (*env)->GetMethodID(env, callbackClass, "haptic_enable", "()V"); + android_haptic_disable = (*env)->GetMethodID(env, callbackClass, "haptic_disable", "()V"); ovrAppThread * appThread = (ovrAppThread *)((size_t)handle); ovrMessage message; diff --git a/Projects/Android/jni/d3es-multithread-master/neo/game/Entity.cpp b/Projects/Android/jni/d3es-multithread-master/neo/game/Entity.cpp index ad8f15f..6fb4c43 100644 --- a/Projects/Android/jni/d3es-multithread-master/neo/game/Entity.cpp +++ b/Projects/Android/jni/d3es-multithread-master/neo/game/Entity.cpp @@ -1631,7 +1631,7 @@ bool idEntity::StartSoundShader( const idSoundShader *shader, const s_channelTyp float distance = direction.Length(); if (distance <= 150.0F) { - bool repeat = (shader->GetParms()->soundShaderFlags & SSF_LOOPING) != 0; + bool looping = (shader->GetParms()->soundShaderFlags & SSF_LOOPING) != 0; direction.Normalize(); idVec3 bodyOrigin = vec3_zero; @@ -1639,16 +1639,15 @@ bool idEntity::StartSoundShader( const idSoundShader *shader, const s_channelTyp player->GetViewPos( bodyOrigin, bodyAxis ); idAngles bodyAng = bodyAxis.ToAngles(); -/* float pitch = direction.ToPitch(); - if (pitch > 180) - pitch -= 360; - float yHeight = idMath::ClampFloat(-0.5f, 0.45f, -pitch / 90.0f);*/ idAngles directionYaw(0, 180 + (direction.ToYaw() - bodyAng.yaw), 0); directionYaw.Normalize360(); //Pass sound on in case it can trigger a haptic event (like doors) - float intensity = 40 + Min((int)(150.0f - distance), 80); - common->HapticEvent(shader->GetName(), 4, repeat ? 1 : 0, intensity, directionYaw.yaw, 0); + float intensity = looping ? (100.0f - distance) : + 40 + Min((int)(150.0f - distance), 80); + + common->HapticEvent(shader->GetName(), 4, looping ? 1 : 0, intensity, + directionYaw.yaw, 0); } } diff --git a/Projects/Android/jni/d3es-multithread-master/neo/game/Player.cpp b/Projects/Android/jni/d3es-multithread-master/neo/game/Player.cpp index 8e9a87f..7eacd75 100644 --- a/Projects/Android/jni/d3es-multithread-master/neo/game/Player.cpp +++ b/Projects/Android/jni/d3es-multithread-master/neo/game/Player.cpp @@ -5741,22 +5741,29 @@ void idPlayerHand::NextWeapon( int dir ) vr_weaponHand.SetInteger( 1 - whichHand ); } + if (currentWeapon == WEAPON_CHAINSAW) + { + //Stop all chainsaw haptics immediately + common->HapticStopEvent("chainsaw_idle"); + common->HapticStopEvent("chainsaw_fire"); + } + idealWeapon = w; weaponSwitchTime = gameLocal.time + WEAPON_SWITCH_DELAY; owner->UpdateHudWeapon( whichHand ); if( vr_debugHands.GetBool() ) common->Printf( "Changing weapon\n" ); - common->HapticEvent("weapon_switch", 0, 0, 100, 0, 0); - if (idealWeapon == WEAPON_CHAINSAW) { + //Start chainsaw idling haptic immediately common->HapticEvent("chainsaw_idle", vr_weaponHand.GetInteger() ? 1 : 2, 1, 100, 0, 0); } - else - { - common->HapticStopEvent("chainsaw_idle"); - } + else + { + + common->HapticEvent("weapon_switch", 0, 0, 100, 0, 0); + } } if( vr_debugHands.GetBool() ) diff --git a/Projects/Android/jni/d3es-multithread-master/neo/sound/snd_world.cpp b/Projects/Android/jni/d3es-multithread-master/neo/sound/snd_world.cpp index b79317a..d0c5215 100644 --- a/Projects/Android/jni/d3es-multithread-master/neo/sound/snd_world.cpp +++ b/Projects/Android/jni/d3es-multithread-master/neo/sound/snd_world.cpp @@ -26,6 +26,7 @@ If you have questions concerning this license or the applicable additional terms =========================================================================== */ +#include #include "sys/platform.h" #include "framework/FileSystem.h" #include "framework/Session.h" @@ -33,6 +34,9 @@ If you have questions concerning this license or the applicable additional terms #include "sound/snd_local.h" +//Haptic Stuff +extern "C" void Doom3Quest_HapticUpdateEvent(const char* event, int intensity, float angle ); + /* ================== idSoundWorldLocal::Init @@ -1589,6 +1593,8 @@ void idSoundWorldLocal::CalcEars( int numSpeakers, idVec3 spatializedOrigin, idV } } +extern idGame * game; + /* =============== idSoundWorldLocal::AddChannelContribution @@ -1755,6 +1761,27 @@ void idSoundWorldLocal::AddChannelContribution( idSoundEmitterLocal *sound, idSo float inputSamples[MIXBUFFER_SAMPLES*2+16]; float *alignedInputSamples = (float *) ( ( ( (intptr_t)inputSamples ) + 15 ) & ~15 ); + if (cvarSystem->GetCVarBool("vr_bhaptics") && + looping && + game != NULL) + { + idVec3 direction = (listenerPos / DOOM_TO_METERS) - sound->origin; + + float distance = direction.Length(); + + if (distance <= 100.0F) { + direction.Normalize(); + idAngles bodyAng = listenerAxis.ToAngles(); + idAngles directionYaw(0, 180 + (direction.ToYaw() - bodyAng.yaw), 0); + directionYaw.Normalize360(); + + int intensity = 100 - distance; + Doom3Quest_HapticUpdateEvent(shader->GetName(), intensity, directionYaw.yaw); + } else{ + Doom3Quest_HapticUpdateEvent(shader->GetName(), 0, 0); + } + } + // // allocate and initialize hardware source // diff --git a/assets/bHaptics/Weapon/Vest/Body_BFG9000_Init.tact b/assets/bHaptics/Weapon/Vest/Body_BFG9000_Init.tact new file mode 100644 index 0000000..08d920b --- /dev/null +++ b/assets/bHaptics/Weapon/Vest/Body_BFG9000_Init.tact @@ -0,0 +1 @@ +{"project":{"createdAt":1614045571509,"description":"","id":"-MUBbDrdhjCIn_K0xHIx","layout":{"layouts":{"VestBack":[{"index":0,"x":0,"y":0},{"index":1,"x":0.333,"y":0},{"index":2,"x":0.667,"y":0},{"index":3,"x":1,"y":0},{"index":4,"x":0,"y":0.25},{"index":5,"x":0.333,"y":0.25},{"index":6,"x":0.667,"y":0.25},{"index":7,"x":1,"y":0.25},{"index":8,"x":0,"y":0.5},{"index":9,"x":0.333,"y":0.5},{"index":10,"x":0.667,"y":0.5},{"index":11,"x":1,"y":0.5},{"index":12,"x":0,"y":0.75},{"index":13,"x":0.333,"y":0.75},{"index":14,"x":0.667,"y":0.75},{"index":15,"x":1,"y":0.75},{"index":16,"x":0,"y":1},{"index":17,"x":0.333,"y":1},{"index":18,"x":0.667,"y":1},{"index":19,"x":1,"y":1}],"VestFront":[{"index":0,"x":0,"y":0},{"index":1,"x":0.333,"y":0},{"index":2,"x":0.667,"y":0},{"index":3,"x":1,"y":0},{"index":4,"x":0,"y":0.25},{"index":5,"x":0.333,"y":0.25},{"index":6,"x":0.667,"y":0.25},{"index":7,"x":1,"y":0.25},{"index":8,"x":0,"y":0.5},{"index":9,"x":0.333,"y":0.5},{"index":10,"x":0.667,"y":0.5},{"index":11,"x":1,"y":0.5},{"index":12,"x":0,"y":0.75},{"index":13,"x":0.333,"y":0.75},{"index":14,"x":0.667,"y":0.75},{"index":15,"x":1,"y":0.75},{"index":16,"x":0,"y":1},{"index":17,"x":0.333,"y":1},{"index":18,"x":0.667,"y":1},{"index":19,"x":1,"y":1}]},"name":"Tactot","type":"Tactot"},"mediaFileDuration":2,"name":"Body_BFG9000_Charge","tracks":[{"effects":[{"modes":{"VestBack":{"dotMode":{"dotConnected":false,"feedback":[]},"mode":"DOT_MODE","pathMode":{"feedback":[{"movingPattern":"CONST_SPEED","playbackType":"NONE","visible":true,"pointList":[]}]}},"VestFront":{"dotMode":{"dotConnected":false,"feedback":[{"endTime":57,"playbackType":"NONE","pointList":[{"index":1,"intensity":0.3}],"startTime":0},{"endTime":114,"playbackType":"NONE","pointList":[{"index":4,"intensity":0.3}],"startTime":57},{"endTime":171,"playbackType":"NONE","pointList":[{"index":0,"intensity":0.3}],"startTime":114},{"endTime":228,"playbackType":"NONE","pointList":[{"index":4,"intensity":0.3}],"startTime":171},{"endTime":285,"playbackType":"NONE","pointList":[{"index":0,"intensity":0.3}],"startTime":228},{"endTime":342,"playbackType":"NONE","pointList":[{"index":1,"intensity":0.3}],"startTime":285},{"endTime":400,"playbackType":"FADE_OUT","pointList":[{"index":0,"intensity":0.3}],"startTime":342}]},"mode":"DOT_MODE","pathMode":{"feedback":[{"movingPattern":"CONST_SPEED","playbackType":"NONE","visible":true,"pointList":[]}]}}},"name":"Effect 1","offsetTime":400,"startTime":0},{"modes":{"VestBack":{"dotMode":{"dotConnected":false,"feedback":[]},"mode":"DOT_MODE","pathMode":{"feedback":[{"movingPattern":"CONST_SPEED","playbackType":"NONE","visible":true,"pointList":[]}]}},"VestFront":{"dotMode":{"dotConnected":false,"feedback":[{"endTime":57,"playbackType":"NONE","pointList":[{"index":1,"intensity":0.5}],"startTime":0},{"endTime":114,"playbackType":"NONE","pointList":[{"index":4,"intensity":0.5}],"startTime":57},{"endTime":171,"playbackType":"NONE","pointList":[{"index":0,"intensity":0.5}],"startTime":114},{"endTime":228,"playbackType":"NONE","pointList":[{"index":4,"intensity":0.5}],"startTime":171},{"endTime":285,"playbackType":"NONE","pointList":[{"index":0,"intensity":0.5}],"startTime":228},{"endTime":342,"playbackType":"NONE","pointList":[{"index":1,"intensity":0.5}],"startTime":285},{"endTime":400,"playbackType":"FADE_OUT","pointList":[{"index":0,"intensity":0.5}],"startTime":342}]},"mode":"DOT_MODE","pathMode":{"feedback":[{"movingPattern":"CONST_SPEED","playbackType":"NONE","visible":true,"pointList":[]}]}}},"name":"Effect 1 copy 4","offsetTime":400,"startTime":497},{"modes":{"VestBack":{"dotMode":{"dotConnected":false,"feedback":[]},"mode":"DOT_MODE","pathMode":{"feedback":[{"movingPattern":"CONST_SPEED","playbackType":"NONE","visible":true,"pointList":[]}]}},"VestFront":{"dotMode":{"dotConnected":false,"feedback":[{"endTime":57,"playbackType":"NONE","pointList":[{"index":1,"intensity":0.6}],"startTime":0},{"endTime":114,"playbackType":"NONE","pointList":[{"index":4,"intensity":0.6}],"startTime":57},{"endTime":171,"playbackType":"NONE","pointList":[{"index":0,"intensity":0.6}],"startTime":114},{"endTime":228,"playbackType":"NONE","pointList":[{"index":4,"intensity":0.6}],"startTime":171},{"endTime":285,"playbackType":"NONE","pointList":[{"index":0,"intensity":0.6}],"startTime":228},{"endTime":342,"playbackType":"NONE","pointList":[{"index":1,"intensity":0.6}],"startTime":285},{"endTime":400,"playbackType":"FADE_OUT","pointList":[{"index":0,"intensity":0.6}],"startTime":342}]},"mode":"DOT_MODE","pathMode":{"feedback":[{"movingPattern":"CONST_SPEED","playbackType":"NONE","visible":true,"pointList":[]}]}}},"name":"Effect 1 copy 6","offsetTime":400,"startTime":976,"trackIndex":0},{"modes":{"VestBack":{"dotMode":{"dotConnected":false,"feedback":[]},"mode":"DOT_MODE","pathMode":{"feedback":[{"movingPattern":"CONST_SPEED","playbackType":"NONE","visible":true,"pointList":[]}]}},"VestFront":{"dotMode":{"dotConnected":false,"feedback":[{"endTime":57,"playbackType":"NONE","pointList":[{"index":1,"intensity":0.8}],"startTime":0},{"endTime":114,"playbackType":"NONE","pointList":[{"index":4,"intensity":0.8}],"startTime":57},{"endTime":171,"playbackType":"NONE","pointList":[{"index":0,"intensity":0.8}],"startTime":114},{"endTime":228,"playbackType":"NONE","pointList":[{"index":4,"intensity":0.8}],"startTime":171},{"endTime":285,"playbackType":"NONE","pointList":[{"index":0,"intensity":0.8}],"startTime":228},{"endTime":342,"playbackType":"NONE","pointList":[{"index":1,"intensity":0.8}],"startTime":285},{"endTime":400,"playbackType":"FADE_OUT","pointList":[{"index":0,"intensity":0.8}],"startTime":342}]},"mode":"DOT_MODE","pathMode":{"feedback":[{"movingPattern":"CONST_SPEED","playbackType":"NONE","visible":true,"pointList":[]}]}}},"name":"Effect 1 copy 8","offsetTime":400,"startTime":1378,"trackIndex":0}],"enable":true},{"effects":[{"modes":{"VestBack":{"dotMode":{"dotConnected":false,"feedback":[]},"mode":"DOT_MODE","pathMode":{"feedback":[{"movingPattern":"CONST_SPEED","playbackType":"NONE","visible":true,"pointList":[]}]}},"VestFront":{"dotMode":{"dotConnected":false,"feedback":[{"endTime":57,"playbackType":"NONE","pointList":[{"index":2,"intensity":0.5}],"startTime":0},{"endTime":114,"playbackType":"NONE","pointList":[{"index":7,"intensity":0.5}],"startTime":57},{"endTime":171,"playbackType":"NONE","pointList":[{"index":3,"intensity":0.5}],"startTime":114},{"endTime":228,"playbackType":"NONE","pointList":[{"index":7,"intensity":0.5}],"startTime":171},{"endTime":285,"playbackType":"NONE","pointList":[{"index":3,"intensity":0.5}],"startTime":228},{"endTime":342,"playbackType":"NONE","pointList":[{"index":2,"intensity":0.5}],"startTime":285},{"endTime":400,"playbackType":"FADE_OUT","pointList":[{"index":3,"intensity":0.5}],"startTime":342}]},"mode":"DOT_MODE","pathMode":{"feedback":[{"movingPattern":"CONST_SPEED","playbackType":"NONE","visible":true,"pointList":[]}]}}},"name":"Effect 1 copy 5","offsetTime":400,"startTime":624},{"modes":{"VestBack":{"dotMode":{"dotConnected":false,"feedback":[]},"mode":"DOT_MODE","pathMode":{"feedback":[{"movingPattern":"CONST_SPEED","playbackType":"NONE","visible":true,"pointList":[]}]}},"VestFront":{"dotMode":{"dotConnected":false,"feedback":[{"endTime":57,"playbackType":"NONE","pointList":[{"index":2,"intensity":0.4}],"startTime":0},{"endTime":114,"playbackType":"NONE","pointList":[{"index":7,"intensity":0.4}],"startTime":57},{"endTime":171,"playbackType":"NONE","pointList":[{"index":3,"intensity":0.4}],"startTime":114},{"endTime":228,"playbackType":"NONE","pointList":[{"index":7,"intensity":0.4}],"startTime":171},{"endTime":285,"playbackType":"NONE","pointList":[{"index":3,"intensity":0.4}],"startTime":228},{"endTime":342,"playbackType":"NONE","pointList":[{"index":2,"intensity":0.4}],"startTime":285},{"endTime":400,"playbackType":"FADE_OUT","pointList":[{"index":3,"intensity":0.4}],"startTime":342}]},"mode":"DOT_MODE","pathMode":{"feedback":[{"movingPattern":"CONST_SPEED","playbackType":"NONE","visible":true,"pointList":[]}]}}},"name":"Effect 1 copy 3","offsetTime":400,"startTime":100},{"modes":{"VestBack":{"dotMode":{"dotConnected":false,"feedback":[]},"mode":"DOT_MODE","pathMode":{"feedback":[{"movingPattern":"CONST_SPEED","playbackType":"NONE","visible":true,"pointList":[]}]}},"VestFront":{"dotMode":{"dotConnected":false,"feedback":[{"endTime":57,"playbackType":"NONE","pointList":[{"index":2,"intensity":0.6}],"startTime":0},{"endTime":114,"playbackType":"NONE","pointList":[{"index":7,"intensity":0.6}],"startTime":57},{"endTime":171,"playbackType":"NONE","pointList":[{"index":3,"intensity":0.6}],"startTime":114},{"endTime":228,"playbackType":"NONE","pointList":[{"index":7,"intensity":0.6}],"startTime":171},{"endTime":285,"playbackType":"NONE","pointList":[{"index":3,"intensity":0.6}],"startTime":228},{"endTime":342,"playbackType":"NONE","pointList":[{"index":2,"intensity":0.6}],"startTime":285},{"endTime":400,"playbackType":"FADE_OUT","pointList":[{"index":3,"intensity":0.6}],"startTime":342}]},"mode":"DOT_MODE","pathMode":{"feedback":[{"movingPattern":"CONST_SPEED","playbackType":"NONE","visible":true,"pointList":[]}]}}},"name":"Effect 1 copy 7","offsetTime":400,"startTime":1101,"trackIndex":1},{"modes":{"VestBack":{"dotMode":{"dotConnected":false,"feedback":[]},"mode":"DOT_MODE","pathMode":{"feedback":[{"movingPattern":"CONST_SPEED","playbackType":"NONE","visible":true,"pointList":[]}]}},"VestFront":{"dotMode":{"dotConnected":false,"feedback":[{"endTime":57,"playbackType":"NONE","pointList":[{"index":2,"intensity":0.8}],"startTime":0},{"endTime":114,"playbackType":"NONE","pointList":[{"index":7,"intensity":0.8}],"startTime":57},{"endTime":171,"playbackType":"NONE","pointList":[{"index":3,"intensity":0.8}],"startTime":114},{"endTime":228,"playbackType":"NONE","pointList":[{"index":7,"intensity":0.8}],"startTime":171},{"endTime":285,"playbackType":"NONE","pointList":[{"index":3,"intensity":0.8}],"startTime":228},{"endTime":342,"playbackType":"NONE","pointList":[{"index":2,"intensity":0.8}],"startTime":285},{"endTime":400,"playbackType":"FADE_OUT","pointList":[{"index":3,"intensity":0.8}],"startTime":342}]},"mode":"DOT_MODE","pathMode":{"feedback":[{"movingPattern":"CONST_SPEED","playbackType":"NONE","visible":true,"pointList":[]}]}}},"name":"Effect 1 copy 9","offsetTime":400,"startTime":1503,"trackIndex":1}],"enable":true}],"updatedAt":1614046039327},"durationMillis":0,"intervalMillis":20,"size":20} \ No newline at end of file diff --git a/assets/bHaptics/Weapon/Vest/Body_Reload.tact b/assets/bHaptics/Weapon/Vest/Body_Reload.tact new file mode 100644 index 0000000..93c5792 --- /dev/null +++ b/assets/bHaptics/Weapon/Vest/Body_Reload.tact @@ -0,0 +1 @@ +{"project":{"createdAt":1614063863216,"description":"","id":"-MUCh-OyqGJ1QiTCDLOU","layout":{"layouts":{"VestBack":[{"index":0,"x":0,"y":0},{"index":1,"x":0.333,"y":0},{"index":2,"x":0.667,"y":0},{"index":3,"x":1,"y":0},{"index":4,"x":0,"y":0.25},{"index":5,"x":0.333,"y":0.25},{"index":6,"x":0.667,"y":0.25},{"index":7,"x":1,"y":0.25},{"index":8,"x":0,"y":0.5},{"index":9,"x":0.333,"y":0.5},{"index":10,"x":0.667,"y":0.5},{"index":11,"x":1,"y":0.5},{"index":12,"x":0,"y":0.75},{"index":13,"x":0.333,"y":0.75},{"index":14,"x":0.667,"y":0.75},{"index":15,"x":1,"y":0.75},{"index":16,"x":0,"y":1},{"index":17,"x":0.333,"y":1},{"index":18,"x":0.667,"y":1},{"index":19,"x":1,"y":1}],"VestFront":[{"index":0,"x":0,"y":0},{"index":1,"x":0.333,"y":0},{"index":2,"x":0.667,"y":0},{"index":3,"x":1,"y":0},{"index":4,"x":0,"y":0.25},{"index":5,"x":0.333,"y":0.25},{"index":6,"x":0.667,"y":0.25},{"index":7,"x":1,"y":0.25},{"index":8,"x":0,"y":0.5},{"index":9,"x":0.333,"y":0.5},{"index":10,"x":0.667,"y":0.5},{"index":11,"x":1,"y":0.5},{"index":12,"x":0,"y":0.75},{"index":13,"x":0.333,"y":0.75},{"index":14,"x":0.667,"y":0.75},{"index":15,"x":1,"y":0.75},{"index":16,"x":0,"y":1},{"index":17,"x":0.333,"y":1},{"index":18,"x":0.667,"y":1},{"index":19,"x":1,"y":1}]},"name":"Tactot","type":"Tactot"},"mediaFileDuration":1,"name":"Body_Reload","tracks":[{"effects":[{"modes":{"VestBack":{"dotMode":{"dotConnected":false,"feedback":[{"endTime":102,"playbackType":"NONE","pointList":[{"index":7,"intensity":0.6}],"startTime":0},{"endTime":204,"playbackType":"FADE_IN","pointList":[{"index":3,"intensity":0.6}],"startTime":102}]},"mode":"DOT_MODE","pathMode":{"feedback":[]}},"VestFront":{"dotMode":{"dotConnected":false,"feedback":[{"endTime":102,"playbackType":"NONE","pointList":[{"index":6,"intensity":0.6},{"index":7,"intensity":0.6}],"startTime":0},{"endTime":204,"playbackType":"FADE_IN","pointList":[{"index":2,"intensity":0.6},{"index":3,"intensity":0.6}],"startTime":102}]},"mode":"DOT_MODE","pathMode":{"feedback":[{"movingPattern":"CONST_SPEED","playbackType":"NONE","visible":true,"pointList":[]}]}}},"name":"Effect 1","offsetTime":204,"startTime":0}],"enable":true},{"enable":true,"effects":[]}],"type":"project","updatedAt":1614063881495},"durationMillis":0,"intervalMillis":20,"size":20} \ No newline at end of file diff --git a/java/com/drbeef/doom3quest/GLES3JNIActivity.java b/java/com/drbeef/doom3quest/GLES3JNIActivity.java index b1d837f..184e826 100644 --- a/java/com/drbeef/doom3quest/GLES3JNIActivity.java +++ b/java/com/drbeef/doom3quest/GLES3JNIActivity.java @@ -2,6 +2,22 @@ package com.drbeef.doom3quest; +import android.Manifest; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.res.AssetManager; +import android.os.Bundle; +import android.support.v4.app.ActivityCompat; +import android.util.Log; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.WindowManager; + +import com.bhaptics.commons.PermissionUtils; +import com.drbeef.doom3quest.bhaptics.bHaptics; + import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; @@ -11,23 +27,6 @@ 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.pm.PackageManager; -import android.content.res.AssetManager; - -import android.media.AudioRecord; -import android.media.AudioTrack; -import android.os.Bundle; -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; @SuppressLint("SdCardPath") public class GLES3JNIActivity extends Activity implements SurfaceHolder.Callback @@ -41,8 +40,6 @@ import static android.system.Os.setenv; private static final String TAG = "Doom3Quest"; private int permissionCount = 0; - private static final int READ_EXTERNAL_STORAGE_PERMISSION_ID = 1; - private static final int WRITE_EXTERNAL_STORAGE_PERMISSION_ID = 2; private String commandLineParams; @@ -50,14 +47,43 @@ import static android.system.Os.setenv; private SurfaceHolder mSurfaceHolder; private long mNativeHandle; - // Audio - protected static AudioTrack mAudioTrack; - protected static AudioRecord mAudioRecord; public void shutdown() { System.exit(0); } + + public void haptic_event(String event, int position, int flags, int intensity, float angle, float yHeight) { + + bHaptics.playHaptic(event, position, flags, intensity, angle, yHeight); + } + + public void haptic_updateevent(String event, int intensity, float angle) { + + bHaptics.updateRepeatingHaptic(event, intensity, angle); + } + + public void haptic_stopevent(String event) { + + bHaptics.stopHaptic(event); + } + + public void haptic_beginframe() { + bHaptics.beginFrame(); + } + + public void haptic_endframe() { + bHaptics.endFrame(); + } + + public void haptic_enable() { + bHaptics.enable(this); + } + + public void haptic_disable() { + bHaptics.disable(); + } + @Override protected void onCreate( Bundle icicle ) { Log.v( TAG, "----------------------------------------------------------------" ); @@ -80,64 +106,44 @@ import static android.system.Os.setenv; checkPermissionsAndInitialize(); } + private void requestPermissions() { + ActivityCompat.requestPermissions(this, + new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.WRITE_EXTERNAL_STORAGE}, + 1); + } + /** Initializes the Activity only if the permission has been granted. */ private void checkPermissionsAndInitialize() { - // Boilerplate for checking runtime permissions in Android. - if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) - != PackageManager.PERMISSION_GRANTED){ - ActivityCompat.requestPermissions( - GLES3JNIActivity.this, - new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, - WRITE_EXTERNAL_STORAGE_PERMISSION_ID); - } - else - { - permissionCount++; - } - - if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) - != PackageManager.PERMISSION_GRANTED) - { - ActivityCompat.requestPermissions( - GLES3JNIActivity.this, - new String[] {Manifest.permission.READ_EXTERNAL_STORAGE}, - READ_EXTERNAL_STORAGE_PERMISSION_ID); - } - else - { - permissionCount++; - } - - if (permissionCount == 2) { - // Permissions have already been granted. + if (PermissionUtils.hasFilePermissions(this)) { create(); + onStart(); + } + else + { + requestPermissions(); } } /** Handles the user accepting the permission. */ @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] results) { - if (requestCode == READ_EXTERNAL_STORAGE_PERMISSION_ID) { + if (requestCode == 1) { + //Quit for now + finish(); + System.exit(0); + } + //Was this a bHaptics FINE LOCATION perms request? + else if (requestCode == 2) { if (results.length > 0 && results[0] == PackageManager.PERMISSION_GRANTED) { - permissionCount++; + //call enable again + bHaptics.enable(this); } else { - System.exit(0); + //Don't do anything here, we can't enable if permissions were denied } } - - if (requestCode == WRITE_EXTERNAL_STORAGE_PERMISSION_ID) { - if (results.length > 0 && results[0] == PackageManager.PERMISSION_GRANTED) { - permissionCount++; - } - else - { - System.exit(0); - } - } - - checkPermissionsAndInitialize(); } public void create() { @@ -194,6 +200,8 @@ import static android.system.Os.setenv; } try { + ApplicationInfo ai = getApplicationInfo(); + setenv("USER_FILES", "/sdcard/Doom3Quest", true); setenv("GAMELIBDIR", getApplicationInfo().nativeLibraryDir, true); setenv("GAMETYPE", "16", true); // hard coded for now @@ -291,7 +299,10 @@ import static android.system.Os.setenv; Log.v( TAG, "GLES3JNIActivity::onStart()" ); super.onStart(); - GLES3JNILib.onStart( mNativeHandle, this ); + if ( mNativeHandle != 0 ) + { + GLES3JNILib.onStart(mNativeHandle, this); + } } @Override protected void onResume() @@ -299,20 +310,29 @@ import static android.system.Os.setenv; Log.v( TAG, "GLES3JNIActivity::onResume()" ); super.onResume(); - GLES3JNILib.onResume( mNativeHandle ); + if ( mNativeHandle != 0 ) + { + GLES3JNILib.onResume(mNativeHandle); + } } @Override protected void onPause() { Log.v( TAG, "GLES3JNIActivity::onPause()" ); - GLES3JNILib.onPause( mNativeHandle ); + if ( mNativeHandle != 0 ) + { + GLES3JNILib.onPause(mNativeHandle); + } super.onPause(); } @Override protected void onStop() { Log.v( TAG, "GLES3JNIActivity::onStop()" ); - GLES3JNILib.onStop( mNativeHandle ); + if ( mNativeHandle != 0 ) + { + GLES3JNILib.onStop(mNativeHandle); + } super.onStop(); } @@ -320,12 +340,17 @@ import static android.system.Os.setenv; { Log.v( TAG, "GLES3JNIActivity::onDestroy()" ); + bHaptics.destroy(); + if ( mSurfaceHolder != null ) { GLES3JNILib.onSurfaceDestroyed( mNativeHandle ); } - GLES3JNILib.onDestroy( mNativeHandle ); + if ( mNativeHandle != 0 ) + { + GLES3JNILib.onDestroy(mNativeHandle); + } super.onDestroy(); mNativeHandle = 0; @@ -360,5 +385,4 @@ import static android.system.Os.setenv; mSurfaceHolder = null; } } - } diff --git a/java/com/drbeef/doom3quest/bhaptics/bHaptics.java b/java/com/drbeef/doom3quest/bhaptics/bHaptics.java index 1dc8295..d29469d 100644 --- a/java/com/drbeef/doom3quest/bhaptics/bHaptics.java +++ b/java/com/drbeef/doom3quest/bhaptics/bHaptics.java @@ -42,16 +42,37 @@ public class bHaptics { this.key = key; this.altKey = altKey; this.group = group; + this.directional = false; this.intensity = intensity; this.duration = duration; + this.rotation = 0; + this.level = 100; + } + + public Haptic(Haptic haptic) { + this.type = haptic.type; + this.key = haptic.key; + this.altKey = haptic.altKey; + this.group = haptic.group; + this.directional = haptic.directional; + this.intensity = haptic.intensity; + this.duration = haptic.duration; + this.rotation = 0; + this.level = 100; } public final String key; public final String altKey; public final String group; - public final float intensity; + + public boolean directional; // can be changed for specific repeating patterns public final float duration; public final PositionType type; + public final float intensity; + + //These two values can be changed over time when playing a looping effect + public float rotation; + public float level; }; private static final String TAG = "Doom3Quest.bHaptics"; @@ -132,14 +153,20 @@ public class bHaptics { registerFromAsset(context, "bHaptics/Interaction/Arms/Healthstation_L.tact", PositionType.ForearmL, "healstation", "pickup"); registerFromAsset(context, "bHaptics/Interaction/Arms/Healthstation_R.tact", PositionType.ForearmR, "healstation", "pickup"); - registerFromAsset(context, "bHaptics/Interaction/Vest/DoorSlide.tact", "doorslide", "door"); + registerFromAsset(context, "bHaptics/Interaction/Vest/DoorSlide.tact", PositionType.Vest, "doorslide", "door", 1.0f, 0.5f); registerFromAsset(context, "bHaptics/Interaction/Vest/Body_Scan.tact", PositionType.Vest, "scan", "environment", 1.0f, 1.15f); registerFromAsset(context, "bHaptics/Interaction/Vest/Body_Scan.tact", PositionType.Vest, "decontaminate", "environment", 0.5f, 0.75f); registerFromAsset(context, "bHaptics/Interaction/Vest/Body_Chamber_Up.tact", "liftup", "environment"); registerFromAsset(context, "bHaptics/Interaction/Vest/Body_Chamber_Down.tact", "liftdown", "environment"); registerFromAsset(context, "bHaptics/Interaction/Vest/Body_Machine.tact", "machine", "environment"); registerFromAsset(context, "bHaptics/Interaction/Vest/Spark.tact", "spark", "environment"); - registerFromAsset(context, "bHaptics/Interaction/Head/Spark.tact", PositionType.Head, "spark", "environment"); + registerFromAsset(context, "bHaptics/Interaction/Head/Spark.tact", PositionType.Head, "spark", "environment", 0.5f, 0.5f); + + //Directional based place holder for looping steam pattern + registerFromAsset(context, "bHaptics/Interaction/Vest/Spark.tact", PositionType.Vest, "steam_loop", "environment", 0.5f, 0.25f); + eventToEffectKeyMap.get("steam_loop").elementAt(0).directional = true; + + registerFromAsset(context, "bHaptics/Interaction/Vest/Spark.tact", "steam_blast", "environment"); registerFromAsset(context, "bHaptics/Interaction/Vest/Body_PDA_Open.tact", "pda_open", "pda"); registerFromAsset(context, "bHaptics/Interaction/Vest/Body_PDA_Open.tact", "pda_close", "pda"); @@ -174,16 +201,16 @@ public class bHaptics { registerFromAsset(context, "bHaptics/Weapon/Arms/ReloadFinish_Mirror.tact", PositionType.ForearmL, "weapon_reload_finish", "weapon"); //Chainsaw Idle - registerFromAsset(context, "bHaptics/Weapon/Vest/Chainsaw_LV1.tact", PositionType.Right, "chainsaw_idle", "weapon"); - registerFromAsset(context, "bHaptics/Weapon/Arms/Chainsaw_LV1.tact", PositionType.ForearmR, "chainsaw_idle", "weapon"); - registerFromAsset(context, "bHaptics/Weapon/Vest/Chainsaw_LV1_Mirror.tact", PositionType.Left, "chainsaw_idle", "weapon"); - registerFromAsset(context, "bHaptics/Weapon/Arms/Chainsaw_LV1_Mirror.tact", PositionType.ForearmL, "chainsaw_idle", "weapon"); + registerFromAsset(context, "bHaptics/Weapon/Vest/Chainsaw_LV2.tact", PositionType.Right, "chainsaw_idle", "weapon"); + registerFromAsset(context, "bHaptics/Weapon/Arms/Chainsaw_LV2.tact", PositionType.ForearmR, "chainsaw_idle", "weapon"); + registerFromAsset(context, "bHaptics/Weapon/Vest/Chainsaw_LV2_Mirror.tact", PositionType.Left, "chainsaw_idle", "weapon"); + registerFromAsset(context, "bHaptics/Weapon/Arms/Chainsaw_LV2_Mirror.tact", PositionType.ForearmL, "chainsaw_idle", "weapon"); //Chainsaw Fire - registerFromAsset(context, "bHaptics/Weapon/Vest/Chainsaw_LV2.tact", PositionType.Right, "chainsaw_fire", "weapon_fire"); - registerFromAsset(context, "bHaptics/Weapon/Arms/Chainsaw_LV2.tact", PositionType.ForearmR, "chainsaw_fire", "weapon_fire"); - registerFromAsset(context, "bHaptics/Weapon/Vest/Chainsaw_LV2_Mirror.tact", PositionType.Left, "chainsaw_fire", "weapon_fire"); - registerFromAsset(context, "bHaptics/Weapon/Arms/Chainsaw_LV2_Mirror.tact", PositionType.ForearmL, "chainsaw_fire", "weapon_fire"); + registerFromAsset(context, "bHaptics/Weapon/Vest/Chainsaw_LV1.tact", PositionType.Right, "chainsaw_fire", "weapon_fire"); + registerFromAsset(context, "bHaptics/Weapon/Arms/Chainsaw_LV1.tact", PositionType.ForearmR, "chainsaw_fire", "weapon_fire"); + registerFromAsset(context, "bHaptics/Weapon/Vest/Chainsaw_LV1_Mirror.tact", PositionType.Left, "chainsaw_fire", "weapon_fire"); + registerFromAsset(context, "bHaptics/Weapon/Arms/Chainsaw_LV1_Mirror.tact", PositionType.ForearmL, "chainsaw_fire", "weapon_fire"); //Fist registerFromAsset(context, "bHaptics/Weapon/Vest/Fist_Mirror.tact", PositionType.Left, "punch", "weapon_fire"); @@ -192,16 +219,16 @@ public class bHaptics { registerFromAsset(context, "bHaptics/Weapon/Arms/Fist.tact", PositionType.ForearmR, "punch", "weapon_fire"); //Pistol - registerFromAsset(context, "bHaptics/Weapon/Vest/Recoil_LV2_Mirror.tact", PositionType.Left, "pistol_fire", "weapon_fire"); - registerFromAsset(context, "bHaptics/Weapon/Arms/Recoil_LV2_Mirror.tact", PositionType.ForearmL, "pistol_fire", "weapon_fire"); - registerFromAsset(context, "bHaptics/Weapon/Vest/Recoil_LV2.tact", PositionType.Right, "pistol_fire", "weapon_fire"); - registerFromAsset(context, "bHaptics/Weapon/Arms/Recoil_LV2.tact", PositionType.ForearmR, "pistol_fire", "weapon_fire"); + registerFromAsset(context, "bHaptics/Weapon/Vest/Recoil_LV3_Mirror.tact", PositionType.Left, "pistol_fire", "weapon_fire"); + registerFromAsset(context, "bHaptics/Weapon/Arms/Recoil_LV3_Mirror.tact", PositionType.ForearmL, "pistol_fire", "weapon_fire"); + registerFromAsset(context, "bHaptics/Weapon/Vest/Recoil_LV3.tact", PositionType.Right, "pistol_fire", "weapon_fire"); + registerFromAsset(context, "bHaptics/Weapon/Arms/Recoil_LV3.tact", PositionType.ForearmR, "pistol_fire", "weapon_fire"); //Shotgun - registerFromAsset(context, "bHaptics/Weapon/Vest/Recoil_LV3_Mirror.tact", PositionType.Left, "shotgun_fire", "weapon_fire"); - registerFromAsset(context, "bHaptics/Weapon/Arms/Recoil_LV3_Mirror.tact", PositionType.ForearmL, "shotgun_fire", "weapon_fire"); - registerFromAsset(context, "bHaptics/Weapon/Vest/Recoil_LV3.tact", PositionType.Right, "shotgun_fire", "weapon_fire"); - registerFromAsset(context, "bHaptics/Weapon/Arms/Recoil_LV3.tact", PositionType.ForearmR, "shotgun_fire", "weapon_fire"); + registerFromAsset(context, "bHaptics/Weapon/Vest/Recoil_LV2_Mirror.tact", PositionType.Left, "shotgun_fire", "weapon_fire"); + registerFromAsset(context, "bHaptics/Weapon/Arms/Recoil_LV2_Mirror.tact", PositionType.ForearmL, "shotgun_fire", "weapon_fire"); + registerFromAsset(context, "bHaptics/Weapon/Vest/Recoil_LV2.tact", PositionType.Right, "shotgun_fire", "weapon_fire"); + registerFromAsset(context, "bHaptics/Weapon/Arms/Recoil_LV2.tact", PositionType.ForearmR, "shotgun_fire", "weapon_fire"); //Plasma Gun registerFromAsset(context, "bHaptics/Weapon/Vest/Recoil_LV1_Mirror.tact", PositionType.Left, "plasmagun_fire", "weapon_fire"); @@ -381,11 +408,19 @@ public class bHaptics { public static void beginFrame() { + Vector toRemove = new Vector<>(); if (enabled && hasPairedDevice) { repeatingHaptics.forEach((key, haptic) -> { - //If a repeating haptic isn't playing, start it again - if (!player.isPlaying(haptic.altKey)) { - player.submitRegistered(haptic.key, haptic.altKey, 100, 1.0f, 0, 0); + if (haptic.level == 0) { + if (player.isPlaying(haptic.altKey)) + { + player.turnOff(haptic.altKey); + } + } + else if (!player.isPlaying(haptic.altKey)) { + //If a repeating haptic isn't playing, start it again with last known values + float flIntensity = ((haptic.level / 100.0F) * haptic.intensity); + player.submitRegistered(haptic.key, haptic.altKey, flIntensity, haptic.duration, haptic.rotation, 0); } }); } @@ -516,7 +551,14 @@ public class bHaptics { //If this is a repeating event, then add to the set to play in begin frame if (flags == 1) { - repeatingHaptics.put(key, haptic); + Haptic repeatingHaptic = new Haptic(haptic); + + if (haptic.directional) { + repeatingHaptic.rotation = flAngle; + } + + repeatingHaptic.level = intensity; + repeatingHaptics.put(key, repeatingHaptic); } else { player.submitRegistered(haptic.key, haptic.altKey, flIntensity, flDuration, flAngle, yHeight); @@ -554,7 +596,7 @@ public class bHaptics { key.contains("explode")) { key = "fireball"; // Just re-use this one } - else if (key.contains("noair")) { + else if (key.contains("noair") || key.contains("gasp")) { key = "noair"; } else if (key.contains("shotgun")) { @@ -595,6 +637,16 @@ public class bHaptics { { key = "spark"; } + else if (key.contains("steam")) + { + if (key.contains("blast") || key.contains("shot") || key.contains("chuff")) { + key = "steam_blast"; + } + else + { + key = "steam_loop"; + } + } else if (key.contains("player") && key.contains("jump")) { key = "jump_start"; @@ -623,6 +675,23 @@ public class bHaptics { } } + public static void updateRepeatingHaptic(String event, float intensity, float angle) { + + if (enabled && hasPairedDevice) { + + String key = getHapticEventKey(event); + + if (repeatingHaptics.containsKey(key)) + { + Haptic haptic = repeatingHaptics.get(key); + if (haptic.directional) { + haptic.rotation = angle; + } + + haptic.level = intensity; + } + } + } public static String read(Context context, String fileName) { try {