diff --git a/Projects/Android/AndroidManifest.xml b/Projects/Android/AndroidManifest.xml index 3bfadba..42196b3 100644 --- a/Projects/Android/AndroidManifest.xml +++ b/Projects/Android/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="48" + android:versionName="1.2.0" android:installLocation="auto" > @@ -10,12 +10,13 @@ - + - + + diff --git a/Projects/Android/build.gradle b/Projects/Android/build.gradle index 75c4eb8..cdd6c61 100644 --- a/Projects/Android/build.gradle +++ b/Projects/Android/build.gradle @@ -23,7 +23,7 @@ android { abiFilters 'armeabi-v7a' } } - minSdkVersion 24 + minSdkVersion 26 targetSdkVersion 26 } @@ -40,13 +40,14 @@ android { sourceCompatibility = '1.8' targetCompatibility = '1.8' } - compileSdkVersion = 24 + compileSdkVersion = 26 buildToolsVersion = '29.0.1' } dependencies { - implementation "com.android.support:support-compat:24.2.0" - implementation "com.android.support:support-core-utils:24.2.0" + 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 { diff --git a/Projects/Android/jni/RTCWVR/RTCWVR_SurfaceView.c b/Projects/Android/jni/RTCWVR/RTCWVR_SurfaceView.c index 8683ec1..b21bb97 100644 --- a/Projects/Android/jni/RTCWVR/RTCWVR_SurfaceView.c +++ b/Projects/Android/jni/RTCWVR/RTCWVR_SurfaceView.c @@ -908,6 +908,155 @@ void RTCWVR_Vibrate( int duration, int channel, float intensity ) vibration_channel_intensity[channel] = intensity; } +void RTCWVR_Haptic( int duration, int channel, float intensity, char *description, float yaw, float height ) +{ + if(strstr(description,"camera_shake") == NULL && strstr(description,"ignore") == NULL && strstr(description,"dead_") == NULL) + Com_Printf("GBRTCW: Vibrate Description: %s (Yaw: %f Pitch: %f)", description, yaw, height); + + if(strcmp(description,"player_dead") == 0) { + RTCWVR_HapticEvent("player_dead", 0, 0, 100.0f * intensity, yaw, height); + } + else if(strcmp(description,"door_kick") == 0) { + RTCWVR_HapticEvent("kick_door", 0, 0, 100.0f * intensity, yaw, height); + } + else if(strcmp(description,"door_open") == 0) { + RTCWVR_HapticEvent("open_door", 0, 0, 100.0f * intensity, yaw, height); + } + else if(strcmp(description,"alarm_on") == 0) { + RTCWVR_HapticEvent("heartbeat", 0, 0, 100.0f * intensity, yaw, height); + } + else if(strcmp(description,"end_alarm") == 0) { + RTCWVR_HapticStopEvent("heartbeat"); + } + else if(strcmp(description,"switch_weapon") == 0 || strcmp(description,"pickup_item") == 0) { + RTCWVR_HapticEvent(description, channel == 1 ? 2 : 1, 0, 100.0f * intensity, 0, 0); + } + else if(strcmp(description,"give_armor") == 0 || strcmp(description,"give_food") == 0 || + strcmp(description,"give_drink") == 0 || strcmp(description,"give_health") == 0 || strcmp(description,"pickup_treasure") == 0) { + RTCWVR_HapticEvent(description, 0, 0, 100.0f * intensity, yaw, height); + } + else if(strstr(description,"damage_") != NULL) { + RTCWVR_HapticEvent(description, 0, 0, 100.0f * intensity, yaw, height); + } + else if(strstr(description,"stop_firing_") != NULL) { + /* + if(strcmp(description,"stop_firing_9") == 0 || strcmp(description,"stop_firing_flames") == 0) { + RTCWVR_HapticStopEvent("fire_flamethrower"); + }*/ + } + else if(strstr(description,"fire_") != NULL) { + if(strcmp(description,"fire_11") == 0 || strcmp(description,"fire_2") == 0) { + RTCWVR_HapticEvent("fire_pistol", channel == 1 ? 2 : 1, 0, 100.0f * intensity, 0, 0); + } + else if(strcmp(description,"fire_3") == 0) { + RTCWVR_HapticEvent("fire_mp40", channel == 1 ? 2 : 1, 0, 100.0f * intensity, 0, 0); + } + else if(strcmp(description,"fire_4") == 0) { + RTCWVR_HapticEvent("fire_mauser", channel == 1 ? 2 : 1, 0, 100.0f * intensity, 0, 0); + } + else if(strcmp(description,"fire_5") == 0 || strcmp(description,"fire_17") == 0) { + RTCWVR_HapticEvent("fire_fg42", channel == 1 ? 2 : 1, 0, 100.0f * intensity, 0, 0); + } + else if(strcmp(description,"fire_6") == 0) { + RTCWVR_HapticEvent("fire_grenadelauncher", channel == 1 ? 2 : 1, 0, 100.0f * intensity, 0, 0); + } + else if(strcmp(description,"fire_7") == 0 || strcmp(description,"fire_rocket") == 0) { + RTCWVR_HapticEvent("fire_panzerfaust", channel == 1 ? 2 : 1, 0, 100.0f * intensity, 0, 0); + } + else if(strcmp(description,"fire_8") == 0) { + RTCWVR_HapticEvent("fire_venom", channel == 1 ? 2 : 1, 0, 100.0f * intensity, 0, 0); + } + else if(strcmp(description,"fire_9") == 0 || strcmp(description,"fire_flames") == 0) { + RTCWVR_HapticEvent("fire_flamethrower", channel == 1 ? 2 : 1, 0, 100.0f * intensity, 0, 0); + } + else if(strcmp(description,"fire_10") == 0 || strcmp(description,"fire_tesla") == 0) { + RTCWVR_HapticEvent("fire_tesla", channel == 1 ? 2 : 1, 0, 100.0f * intensity, 0, 0); + } + else if(strcmp(description,"fire_12") == 0) { + RTCWVR_HapticEvent("fire_thompson", channel == 1 ? 2 : 1, 0, 100.0f * intensity, 0, 0); + } + else if(strcmp(description,"fire_13") == 0) { + RTCWVR_HapticEvent("fire_garand", channel == 1 ? 2 : 1, 0, 100.0f * intensity, 0, 0); + } + else if(strcmp(description,"fire_14") == 0) { + RTCWVR_HapticEvent("fire_grenade", channel == 1 ? 2 : 1, 0, 100.0f * intensity, 0, 0); + } + else if(strcmp(description,"fire_15") == 0) { + RTCWVR_HapticEvent("fire_sniper", channel == 1 ? 2 : 1, 0, 100.0f * intensity, 0, 0); + } + else if(strcmp(description,"fire_16") == 0) { + RTCWVR_HapticEvent("fire_snooperscope", channel == 1 ? 2 : 1, 0, 100.0f * intensity, 0, 0); + } + else if(strcmp(description,"fire_18") == 0) { + RTCWVR_HapticEvent("fire_sten", channel == 1 ? 2 : 1, 0, 100.0f * intensity, 0, 0); + } + else if(strcmp(description,"fire_19") == 0) { + RTCWVR_HapticEvent("fire_silencer", channel == 1 ? 2 : 1, 0, 100.0f * intensity, 0, 0); + } + else if(strcmp(description,"fire_20") == 0) { + //Plays on 0 position (Vest) (not left or right) + RTCWVR_HapticEvent("fire_akimbo", 0, 0, 100.0f * intensity, 0, 0); + } + } + else if(strcmp(description,"knife_hit") == 0) { + RTCWVR_HapticEvent("knife_hit", channel == 1 ? 2 : 1, 0, 100.0f * intensity, 0, 0); + } + else if(strcmp(description,"camera_shake_left") == 0) { + RTCWVR_HapticEvent("rumble_front", 0, 0, 100.0f * intensity, yaw, height); + } + else if(strcmp(description,"camera_shake_right") == 0) { + RTCWVR_HapticEvent("rumble_back", 0, 0, 100.0f * intensity, yaw, height); + } + else { + if(strstr(description,"ignore") == NULL && + strstr(description,"dead") == NULL) + Com_Printf("Missing Haptic: %s", description); + } +} + +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 RTCWVR_HapticEvent(const char* event, int position, int flags, int intensity, float angle, float yHeight ) +{ + //Com_Printf( "GBRTCW: Vibrate Event Fired: %s", event ); + jni_haptic_event(event, position, flags, intensity, angle, yHeight); +} + +void RTCWVR_HapticUpdateEvent(const char* event, int intensity, float angle ) +{ + jni_haptic_updateevent(event, intensity, angle); +} + +void RTCWVR_HapticEndFrame() +{ + jni_haptic_endframe(); +} + +void RTCWVR_HapticStopEvent(const char* event) +{ + jni_haptic_stopevent(event); +} + +void RTCWVR_HapticEnable() +{ + static bool firstTime = true; + if (firstTime) { + jni_haptic_enable(); + firstTime = false; + jni_haptic_event("fire_pistol", 0, 0, 100, 0, 0); + } +} + +void RTCWVR_HapticDisable() +{ + jni_haptic_disable(); +} + void RTCWVR_GetMove(float *forward, float *side, float *pos_forward, float *pos_side, float *up, float *yaw, float *pitch, float *roll) { @@ -1503,7 +1652,7 @@ void * AppThreadFunction(void * parm ) { // This app will handle android gamepad events itself. vrapi_SetPropertyInt(&gAppState.Java, VRAPI_EAT_NATIVE_GAMEPAD_EVENTS, 0); - //Set device defaults + //Set device defaults if (vrapi_GetSystemPropertyInt(&java, VRAPI_SYS_PROP_DEVICE_TYPE) == VRAPI_DEVICE_TYPE_OCULUSQUEST) { if (SS_MULTIPLIER == 0.0f) @@ -1515,12 +1664,12 @@ void * AppThreadFunction(void * parm ) { { if (SS_MULTIPLIER == 0.0f) { - //Lower to allow 90hz to work nicely - SS_MULTIPLIER = 1.0f; + //GB Override as refresh is now 72 by default as we decided a higher res is better as 90hz has stutters + SS_MULTIPLIER = 1.35f; } - else if (SS_MULTIPLIER > 1.2F) + else if (SS_MULTIPLIER > 1.5f) { - SS_MULTIPLIER = 1.2f; + SS_MULTIPLIER = 1.5f; } } else { //Don't know what headset this is!? abort @@ -1572,7 +1721,7 @@ void * AppThreadFunction(void * parm ) { vrapi_GetSystemPropertyFloatArray(&java, VRAPI_SYS_PROP_SUPPORTED_DISPLAY_REFRESH_RATES, &refreshRatesArray[0], numberOfRefreshRates); for (int i = 0; i < numberOfRefreshRates; i++) { - ALOGV("Supported refresh rate : %s Hz", refreshRatesArray[i]); + ALOGV("Supported refresh rate : %d Hz", refreshRatesArray[i]); if (maximumSupportRefresh < refreshRatesArray[i]) { maximumSupportRefresh = refreshRatesArray[i]; } @@ -1585,7 +1734,7 @@ void * AppThreadFunction(void * parm ) { if (REFRESH == 0 || REFRESH > maximumSupportRefresh) { - REFRESH = maximumSupportRefresh; + REFRESH = 72.0; } //----------------------------------------------------------------------------------------------------------- @@ -1716,12 +1865,14 @@ void RTCWVR_getTrackedRemotesOrientation() {//Get info for tracked remotes switch (vr_control_scheme->integer) { case RIGHT_HANDED_DEFAULT: - HandleInput_Default(&rightTrackedRemoteState_new, &rightTrackedRemoteState_old, &rightRemoteTracking_new, + HandleInput_Default(&footTrackedRemoteState_new, &footTrackedRemoteState_old, + &rightTrackedRemoteState_new, &rightTrackedRemoteState_old, &rightRemoteTracking_new, &leftTrackedRemoteState_new, &leftTrackedRemoteState_old, &leftRemoteTracking_new, ovrButton_A, ovrButton_B, ovrButton_X, ovrButton_Y); break; case LEFT_HANDED_DEFAULT: - HandleInput_Default(&leftTrackedRemoteState_new, &leftTrackedRemoteState_old, &leftRemoteTracking_new, + HandleInput_Default(&footTrackedRemoteState_new, &footTrackedRemoteState_old, + &leftTrackedRemoteState_new, &leftTrackedRemoteState_old, &leftRemoteTracking_new, &rightTrackedRemoteState_new, &rightTrackedRemoteState_old, &rightRemoteTracking_new, ovrButton_X, ovrButton_Y, ovrButton_A, ovrButton_B); break; @@ -1809,6 +1960,7 @@ void RTCWVR_submitFrame() RTCWVR_incrementFrameIndex(); + RTCWVR_HapticEndFrame(); } static void ovrAppThread_Create( ovrAppThread * appThread, JNIEnv * env, jobject activityObject, jclass activityClass ) @@ -1845,8 +1997,14 @@ Activity lifecycle jmethodID 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; static JavaVM *jVM; -static jobject shutdownCallbackObj=0; +static jobject jniCallbackObj=0; void jni_shutdown() { @@ -1857,7 +2015,88 @@ 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_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); } int JNI_OnLoad(JavaVM* vm, void* reserved) @@ -1953,10 +2192,16 @@ JNIEXPORT void JNICALL Java_com_drbeef_rtcwquest_GLES3JNILib_onStart( JNIEnv * e 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_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/RTCWVR/VrCommon.h b/Projects/Android/jni/RTCWVR/VrCommon.h index 3164d2b..948ca0d 100644 --- a/Projects/Android/jni/RTCWVR/VrCommon.h +++ b/Projects/Android/jni/RTCWVR/VrCommon.h @@ -60,6 +60,13 @@ int GetRefresh(); qboolean RTCWVR_useScreenLayer(); void RTCWVR_GetScreenRes(int *width, int *height); void RTCWVR_Vibrate(int duration, int channel, float intensity ); +void RTCWVR_Haptic(int duration, int channel, float intensity, char *description, float yaw, float height); +void RTCWVR_HapticEvent(const char* event, int position, int flags, int intensity, float angle, float yHeight ); +void RTCWVR_HapticUpdateEvent(const char* event, int intensity, float angle ); +void RTCWVR_HapticEndFrame(); +void RTCWVR_HapticStopEvent(const char* event); +void RTCWVR_HapticEnable(); +void RTCWVR_HapticDisable(); qboolean RTCWVR_processMessageQueue(); void RTCWVR_FrameSetup(); void RTCWVR_setUseScreenLayer(qboolean use); diff --git a/Projects/Android/jni/RTCWVR/VrCompositor.c b/Projects/Android/jni/RTCWVR/VrCompositor.c index 28125db..060dabf 100644 --- a/Projects/Android/jni/RTCWVR/VrCompositor.c +++ b/Projects/Android/jni/RTCWVR/VrCompositor.c @@ -154,7 +154,13 @@ ovrLayerCylinder2 BuildCylinderLayer( ovrRenderer * cylinderRenderer, const float density = 4500.0f; const float rotateYaw = 0.0f; const float radius = 4.0f; - const float distance = vr_screen_dist ? -vr_screen_dist->value : -3.5f; + //GB Hacky Override + float screen_offset = 0; + if(textureWidth > 1900) + { + screen_offset = -2.625f; + } + const float distance = vr_screen_dist ? -vr_screen_dist->value + screen_offset : -3.5f + screen_offset; const ovrVector3f translation = { 0.0f, playerHeight/2, distance }; diff --git a/Projects/Android/jni/RTCWVR/VrInput.h b/Projects/Android/jni/RTCWVR/VrInput.h index 54634d0..781ce62 100644 --- a/Projects/Android/jni/RTCWVR/VrInput.h +++ b/Projects/Android/jni/RTCWVR/VrInput.h @@ -21,6 +21,9 @@ ovrInputStateTrackedRemote rightTrackedRemoteState_old; ovrInputStateTrackedRemote rightTrackedRemoteState_new; ovrTracking rightRemoteTracking_new; +ovrInputStateGamepad footTrackedRemoteState_old; +ovrInputStateGamepad footTrackedRemoteState_new; + ovrDeviceID controllerIDs[2]; float remote_movementSideways; @@ -35,7 +38,8 @@ void sendButtonActionSimple(const char* action); void acquireTrackedRemotesData(const ovrMobile *Ovr, double displayTime); -void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew, ovrInputStateTrackedRemote *pDominantTrackedRemoteOld, ovrTracking* pDominantTracking, +void HandleInput_Default( ovrInputStateGamepad *pFootTrackingNew, ovrInputStateGamepad *pFootTrackingOld, + ovrInputStateTrackedRemote *pDominantTrackedRemoteNew, ovrInputStateTrackedRemote *pDominantTrackedRemoteOld, ovrTracking* pDominantTracking, ovrInputStateTrackedRemote *pOffTrackedRemoteNew, ovrInputStateTrackedRemote *pOffTrackedRemoteOld, ovrTracking* pOffTracking, int domButton1, int domButton2, int offButton1, int offButton2 ); diff --git a/Projects/Android/jni/RTCWVR/VrInputCommon.c b/Projects/Android/jni/RTCWVR/VrInputCommon.c index 1396ba9..7bded56 100644 --- a/Projects/Android/jni/RTCWVR/VrInputCommon.c +++ b/Projects/Android/jni/RTCWVR/VrInputCommon.c @@ -94,7 +94,22 @@ void acquireTrackedRemotesData(const ovrMobile *Ovr, double displayTime) {//The break; } - if (cap.Type == ovrControllerType_TrackedRemote) { + if (cap.Type == ovrControllerType_Gamepad) { + + ovrInputGamepadCapabilities remoteCaps; + remoteCaps.Header = cap; + if (vrapi_GetInputDeviceCapabilities(Ovr, &remoteCaps.Header) >= 0) { + // remote is connected + ovrInputStateGamepad remoteState; + remoteState.Header.ControllerType = ovrControllerType_Gamepad; + if ( vrapi_GetCurrentInputState( Ovr, cap.DeviceID, &remoteState.Header ) >= 0 ) + { + // act on device state returned in remoteState + footTrackedRemoteState_new = remoteState; + } + } + } + else if (cap.Type == ovrControllerType_TrackedRemote) { ovrTracking remoteTracking; ovrInputStateTrackedRemote trackedRemoteState; trackedRemoteState.Header.ControllerType = ovrControllerType_TrackedRemote; diff --git a/Projects/Android/jni/RTCWVR/VrInputDefault.c b/Projects/Android/jni/RTCWVR/VrInputDefault.c index 74d6542..9eabd48 100644 --- a/Projects/Android/jni/RTCWVR/VrInputDefault.c +++ b/Projects/Android/jni/RTCWVR/VrInputDefault.c @@ -25,7 +25,10 @@ Authors : Simon Brown void SV_Trace( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask, int capsule ); -void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew, ovrInputStateTrackedRemote *pDominantTrackedRemoteOld, ovrTracking* pDominantTracking, +void RTCWVR_HapticEvent(const char* event, int position, int flags, int intensity, float angle, float yHeight ); + +void HandleInput_Default( ovrInputStateGamepad *pFootTrackingNew, ovrInputStateGamepad *pFootTrackingOld, + ovrInputStateTrackedRemote *pDominantTrackedRemoteNew, ovrInputStateTrackedRemote *pDominantTrackedRemoteOld, ovrTracking* pDominantTracking, ovrInputStateTrackedRemote *pOffTrackedRemoteNew, ovrInputStateTrackedRemote *pOffTrackedRemoteOld, ovrTracking* pOffTracking, int domButton1, int domButton2, int offButton1, int offButton2 ) @@ -442,6 +445,8 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew, } + + //We need to record if we have started firing primary so that releasing trigger will stop firing, if user has pushed grip //in meantime, then it wouldn't stop the gun firing and it would get stuck static qboolean firing = false; @@ -547,8 +552,8 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew, //Apply a filter and quadratic scaler so small movements are easier to make float dist = length(pSecondaryJoystick->x, pSecondaryJoystick->y); float nlf = nonLinearFilter(dist); - float x = nlf * pSecondaryJoystick->x; - float y = nlf * pSecondaryJoystick->y; + float x = (nlf * pSecondaryJoystick->x) + pFootTrackingNew->LeftJoystick.x; + float y = (nlf * pSecondaryJoystick->y) - pFootTrackingNew->LeftJoystick.y; vr.player_moving = (fabs(x) + fabs(y)) > 0.05f; @@ -614,6 +619,7 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew, handleTrackedControllerButton(pOffTrackedRemoteNew, pOffTrackedRemoteOld, ovrButton_Trigger, K_SHIFT); + } else { if (pOffTrackedRemoteNew->Buttons & ovrButton_Trigger) { diff --git a/Projects/Android/jni/rtcw/src/cgame/cg_draw.c b/Projects/Android/jni/rtcw/src/cgame/cg_draw.c index 0aac793..c6e501c 100644 --- a/Projects/Android/jni/rtcw/src/cgame/cg_draw.c +++ b/Projects/Android/jni/rtcw/src/cgame/cg_draw.c @@ -3575,8 +3575,12 @@ void CG_ApplyShakeCamera() { if (VectorLength(cg.cameraShakeAngles) > 0.1f) { - trap_Vibrate(10, 0, Com_Clamp(0.0f, 1.0f, fabs(cg.cameraShakeAngles[0]))); - trap_Vibrate(10, 1, Com_Clamp(0.0f, 1.0f, fabs(cg.cameraShakeAngles[1]))); + // up/down = cg.cameraShakeAngles[0] + // left/right = cg.cameraShakeAngles[1]; + // roll cg.cameraShakeAngles[2] + + trap_Vibrate(10, 0, Com_Clamp(0.0f, 1.0f, fabs(cg.cameraShakeAngles[0])),"camera_shake_left",270,fabs(cg.cameraShakeAngles[0])); + trap_Vibrate(10, 0, Com_Clamp(0.0f, 1.0f, fabs(cg.cameraShakeAngles[1])),"camera_shake_right",90,fabs(cg.cameraShakeAngles[0])); } } diff --git a/Projects/Android/jni/rtcw/src/cgame/cg_effects.c b/Projects/Android/jni/rtcw/src/cgame/cg_effects.c index 6d8a5b4..46a0405 100644 --- a/Projects/Android/jni/rtcw/src/cgame/cg_effects.c +++ b/Projects/Android/jni/rtcw/src/cgame/cg_effects.c @@ -1706,6 +1706,8 @@ void CG_RumbleEfx( float pitch, float yaw ) { VectorCopy( recoil, cg.kickAVel ); // set the recoil cg.recoilPitch -= pitchRecoilAdd; + + } diff --git a/Projects/Android/jni/rtcw/src/cgame/cg_event.c b/Projects/Android/jni/rtcw/src/cgame/cg_event.c index a26961e..c037381 100644 --- a/Projects/Android/jni/rtcw/src/cgame/cg_event.c +++ b/Projects/Android/jni/rtcw/src/cgame/cg_event.c @@ -32,9 +32,10 @@ If you have questions concerning this license or the applicable additional terms #include "cg_local.h" #include "../ui/ui_shared.h" // for Menus_CloseAll() +#include "../../../RTCWVR/VrClientInfo.h" extern int hWeaponSnd; - +extern vr_client_info_t *cgVR; extern void CG_Tracer( vec3_t source, vec3_t dest, int sparks ); //========================================================================== @@ -1979,17 +1980,17 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { // client will get this message if reloading while using an alternate weapon // client should voluntarily switch back to primary at that point switch ( es->weapon ) { - case WP_SNOOPERSCOPE: - newweap = WP_GARAND; - break; - case WP_SNIPERRIFLE: - newweap = WP_MAUSER; - break; - case WP_FG42SCOPE: - newweap = WP_FG42; - break; - default: - break; + case WP_SNOOPERSCOPE: + newweap = WP_GARAND; + break; + case WP_SNIPERRIFLE: + newweap = WP_MAUSER; + break; + case WP_FG42SCOPE: + newweap = WP_FG42; + break; + default: + break; } // TTimo @@ -2239,12 +2240,14 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { ByteToDir( es->eventParm, dir ); CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qfalse, ENTITYNUM_WORLD, qtrue, es->otherEntityNum2 ); trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.fkickwall ); + trap_Vibrate(1, 1, 0.8, "door_kick", 0.0, -0.5); break; case EV_WOLFKICK_HIT_FLESH: DEBUGNAME( "EV_WOLFKICK_HIT_FLESH" ); CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qtrue, es->eventParm, qtrue, es->otherEntityNum2 ); trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.fkickflesh ); + trap_Vibrate(1, 1, 0.7, "door_kick", 0.0, -0.5); break; case EV_WOLFKICK_MISS: diff --git a/Projects/Android/jni/rtcw/src/cgame/cg_local.h b/Projects/Android/jni/rtcw/src/cgame/cg_local.h index 13e0df0..9e6ded2 100644 --- a/Projects/Android/jni/rtcw/src/cgame/cg_local.h +++ b/Projects/Android/jni/rtcw/src/cgame/cg_local.h @@ -2458,7 +2458,9 @@ int trap_Key_GetCatcher( void ); void trap_Key_SetCatcher( int catcher ); int trap_Key_GetKey( const char *binding ); -int trap_Vibrate(int duration, int channel, float intensity ); +int trap_Haptic( int duration, int channel, float intensity, char *description, float yaw, float height); +int trap_Vibrate( int duration, int channel, float intensity, char *description, float yaw, float height); +int trap_EnableHaptics(); // RF void trap_SendMoveSpeedsToGame( int entnum, char *movespeeds ); diff --git a/Projects/Android/jni/rtcw/src/cgame/cg_main.c b/Projects/Android/jni/rtcw/src/cgame/cg_main.c index 4a034b5..0595d9f 100644 --- a/Projects/Android/jni/rtcw/src/cgame/cg_main.c +++ b/Projects/Android/jni/rtcw/src/cgame/cg_main.c @@ -2454,6 +2454,9 @@ void CG_Init( int serverMessageNum, int serverCommandSequence ) { } // jpw // -NERVE - SMF + + //GB - Turn on haptics here - because reasons + trap_EnableHaptics(); } /* diff --git a/Projects/Android/jni/rtcw/src/cgame/cg_playerstate.c b/Projects/Android/jni/rtcw/src/cgame/cg_playerstate.c index e19b5a4..910cd32 100644 --- a/Projects/Android/jni/rtcw/src/cgame/cg_playerstate.c +++ b/Projects/Android/jni/rtcw/src/cgame/cg_playerstate.c @@ -221,6 +221,13 @@ void CG_DamageFeedback( int yawByte, int pitchByte, int damage ) { vd->damageDuration = kick * 50 * ( 1 + 2 * ( !vd->damageX && !vd->damageY ) ); cg.damageTime = cg.snap->serverTime; cg.damageIndex = slot; + + //GB - Add a haptic event + //Ensure a decent level of haptic feedback for any damage + //float hapticLevel = 80 + min(damage * 4, 120.0); + + //Indicate head damage if appropriate + //RTCWVR_HapticEvent("damage", 0, 0, hapticLevel, yaw, pitch); } diff --git a/Projects/Android/jni/rtcw/src/cgame/cg_public.h b/Projects/Android/jni/rtcw/src/cgame/cg_public.h index 51b93cc..83a1f64 100644 --- a/Projects/Android/jni/rtcw/src/cgame/cg_public.h +++ b/Projects/Android/jni/rtcw/src/cgame/cg_public.h @@ -219,7 +219,9 @@ typedef enum { CG_GETMODELINFO, - CG_HAPTIC + CG_HAPTIC, + CG_HAPTICENABLE, + CG_HAPTICTRIGGER } cgameImport_t; diff --git a/Projects/Android/jni/rtcw/src/cgame/cg_syscalls.c b/Projects/Android/jni/rtcw/src/cgame/cg_syscalls.c index a98576f..6f744cf 100644 --- a/Projects/Android/jni/rtcw/src/cgame/cg_syscalls.c +++ b/Projects/Android/jni/rtcw/src/cgame/cg_syscalls.c @@ -549,6 +549,14 @@ qboolean trap_GetModelInfo( int clientNum, char *modelName, animModelInfo_t **mo return syscall( CG_GETMODELINFO, clientNum, modelName, modelInfo ); } -int trap_Vibrate( int duration, int channel, float intensity ) { - return syscall( CG_HAPTIC, duration, channel, PASSFLOAT(intensity) ); +int trap_Vibrate( int duration, int channel, float intensity, char *description, float yaw, float height) { + return syscall( CG_HAPTIC, duration, channel, PASSFLOAT(intensity), description, PASSFLOAT(yaw), PASSFLOAT(height)); +} + +int trap_Haptic( int duration, int channel, float intensity, char *description, float yaw, float height) { + return syscall( CG_HAPTICTRIGGER, duration, channel, PASSFLOAT(intensity), description, PASSFLOAT(yaw), PASSFLOAT(height)); +} + +int trap_EnableHaptics() { + return syscall( CG_HAPTICENABLE ); } diff --git a/Projects/Android/jni/rtcw/src/cgame/cg_view.c b/Projects/Android/jni/rtcw/src/cgame/cg_view.c index 8e9eb70..9274b4a 100644 --- a/Projects/Android/jni/rtcw/src/cgame/cg_view.c +++ b/Projects/Android/jni/rtcw/src/cgame/cg_view.c @@ -1666,8 +1666,8 @@ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demo //Don't allow long running haptics to continue once dead if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) { - trap_Vibrate(0, 0, 0.0); - trap_Vibrate(0, 1, 0.0); + trap_Vibrate(0, 0, 0.0, "dead_left", 0.0, 0.0); + trap_Vibrate(0, 1, 0.0, "dead_right", 0.0, 0.0); } DEBUGTIME diff --git a/Projects/Android/jni/rtcw/src/cgame/cg_weapons.c b/Projects/Android/jni/rtcw/src/cgame/cg_weapons.c index 9cb9c13..2d3f1d9 100644 --- a/Projects/Android/jni/rtcw/src/cgame/cg_weapons.c +++ b/Projects/Android/jni/rtcw/src/cgame/cg_weapons.c @@ -2229,10 +2229,10 @@ static void CG_FlamethrowerFlame( centity_t *cent, vec3_t origin ) { CG_FireFlameChunks(cent, origin, angles, 1.0, qtrue, 1); - trap_Vibrate(-1, cgVR->right_handed ? 1 : 0, 0.6); + trap_Vibrate(-1, cgVR->right_handed ? 1 : 0, 0.6, "fire_flames", 0.0, 0.0); if (cgVR->weapon_stabilised) { - trap_Vibrate(-1, cgVR->right_handed ? 0 : 1, 0.5); + trap_Vibrate(-1, cgVR->right_handed ? 0 : 1, 0.5, "fire_flames", 0.0, 0.0); } } @@ -2776,10 +2776,10 @@ void CG_PlayerTeslaCoilFire( centity_t *cent, vec3_t flashorigin ) { trap_R_AddLightToScene( tr.endpos, 256 + 600 * tr.fraction, 0.2, 0.6, 1, 0 ); } - trap_Vibrate(-1, cgVR->right_handed ? 1 : 0, 0.8); + trap_Vibrate(-1, cgVR->right_handed ? 1 : 0, 0.8, "fire_tesla", 0.0, 0.0); if (cgVR->weapon_stabilised) { - trap_Vibrate(-1, cgVR->right_handed ? 0 : 1, 0.8); + trap_Vibrate(-1, cgVR->right_handed ? 0 : 1, 0.8, "fire_tesla", 0.0, 0.0); } // shake the camera a bit @@ -3378,8 +3378,11 @@ void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent if (wasfiring) { //Stop haptics - trap_Vibrate(0, 0, 0.0); - trap_Vibrate(0, 1, 0.0); + char *fire_command = (char*)malloc(8 * sizeof(char)); + //sprintf(fire_command, "stop_firing_%i", weaponNum); + //trap_Vibrate(0, 0, 0.0, fire_command, 0.0, 0.0); + trap_Vibrate(0, 0, 0.0, "ignore", 0.0, 0.0); + trap_Vibrate(0, 1, 0.0, "ignore", 0.0, 0.0); wasfiring = qfalse; } } @@ -4356,6 +4359,7 @@ void CG_SetSniperZoom( int lastweap, int newweap ) { default: Com_Printf("**WEAPON EVENT** cgVR->scopeengaged = qfalse"); cgVR->scopeengaged = qfalse; + trap_Haptic(1, cgVR->right_handed ? 1 : 0, 0.7f, "switch_weapon", 0.0f, 0.0f); break; } @@ -4369,6 +4373,7 @@ void CG_SetSniperZoom( int lastweap, int newweap ) { switch ( newweap ) { default: + return; // no sniper zoom, get out. case WP_SNIPERRIFLE: diff --git a/Projects/Android/jni/rtcw/src/client/cl_cgame.c b/Projects/Android/jni/rtcw/src/client/cl_cgame.c index 903733c..7d374bf 100644 --- a/Projects/Android/jni/rtcw/src/client/cl_cgame.c +++ b/Projects/Android/jni/rtcw/src/client/cl_cgame.c @@ -45,7 +45,13 @@ extern qboolean getCameraInfo( int camNum, int time, vec3_t *origin, vec3_t *ang extern void SV_SendMoveSpeedsToGame( int entnum, char *text ); extern qboolean SV_GetModelInfo( int clientNum, char *modelName, animModelInfo_t **modelInfo ); void RTCWVR_Vibrate(int duration, int channel, float intensity ); - +void RTCWVR_Haptic(int duration, int channel, float intensity, char *description, float yaw, float height); +void RTCWVR_HapticEvent(const char* event, int position, int flags, int intensity, float angle, float yHeight ); +void RTCWVR_HapticUpdateEvent(const char* event, int intensity, float angle ); +void RTCWVR_HapticEndFrame(); +void RTCWVR_HapticStopEvent(const char* event); +void RTCWVR_HapticEnable(); +void RTCWVR_HapticDisable(); /* ==================== @@ -857,7 +863,26 @@ int CL_CgameSystemCalls( int *args ) { return SV_GetModelInfo( args[1], VMA( 2 ), VMA( 3 ) ); case CG_HAPTIC: + //args[2] = Right or left channel (1 = Right / 0 = left) + //VMF(3) = Intensity + //VMA(4) = Description + //VMF(5) = Yaw + //VMF(6) = Height + RTCWVR_Vibrate( args[1], args[2], VMF( 3 ) ); + + RTCWVR_Haptic( args[1], args[2], VMF( 3 ), VMA(4), VMF(5), VMF(6) ); + return 0; + case CG_HAPTICTRIGGER: + //VMF(1) = Intensity + //VMA(2) = Description + //VMF(3) = Yaw + //VMF(4) = Height + + RTCWVR_Haptic( args[1], args[2], VMF( 3 ), VMA(4), VMF(5), VMF(6) ); + return 0; + case CG_HAPTICENABLE: + RTCWVR_HapticEnable(); return 0; default: diff --git a/Projects/Android/jni/rtcw/src/client/cl_scrn.c b/Projects/Android/jni/rtcw/src/client/cl_scrn.c index 56a83bd..8bc46f2 100644 --- a/Projects/Android/jni/rtcw/src/client/cl_scrn.c +++ b/Projects/Android/jni/rtcw/src/client/cl_scrn.c @@ -557,6 +557,7 @@ void SCR_UpdateScreen( void ) { recursive = 1; RTCWVR_FrameSetup(); + RTCWVR_processMessageQueue(); //Get controller state here diff --git a/Projects/Android/jni/rtcw/src/game/bg_public.h b/Projects/Android/jni/rtcw/src/game/bg_public.h index cd98d36..ea24942 100644 --- a/Projects/Android/jni/rtcw/src/game/bg_public.h +++ b/Projects/Android/jni/rtcw/src/game/bg_public.h @@ -543,16 +543,16 @@ typedef enum { WP_VENOM, // 8 WP_FLAMETHROWER, // 9 WP_TESLA, // 10 -// WP_SPEARGUN, // 11 +// WP_SPEARGUN, // __ // weapon keys only go 1-0, so put the alternates above that (since selection will be a double click on the german weapon key) // American equivalents -// WP_KNIFE2, // 12 +// WP_KNIFE2, // __ WP_COLT, // 11 equivalent american weapon to german luger WP_THOMPSON, // 12 equivalent american weapon to german mp40 WP_GARAND, // 13 equivalent american weapon to german mauser -// WP_BAR, // 16 equivalent american weapon to german fg42 +// WP_BAR, // __ equivalent american weapon to german fg42 WP_GRENADE_PINEAPPLE, // 14 // WP_ROCKET_LAUNCHER, // 18 equivalent american weapon to german panzerfaust diff --git a/Projects/Android/jni/rtcw/src/game/g_active.c b/Projects/Android/jni/rtcw/src/game/g_active.c index 7e45125..a6cdbb6 100644 --- a/Projects/Android/jni/rtcw/src/game/g_active.c +++ b/Projects/Android/jni/rtcw/src/game/g_active.c @@ -60,7 +60,7 @@ void P_DamageFeedback( gentity_t *player ) { // total points of damage shot at the player this frame count = client->damage_blood + client->damage_armor; - if ( count == 0 ) { + if ( count == 0 ) { return; // didn't take any damage } @@ -95,8 +95,137 @@ void P_DamageFeedback( gentity_t *player ) { client->ps.damageCount = count; if (!client->ps.aiChar) { - trap_Vibrate(1000, 1, (count / 255.0) + 0.5f); - trap_Vibrate(1000, 0, (count / 255.0) + 0.5f); + vec3_t viewangle; + float_t pitch, yaw; + //pitch = (abs(angles[PITCH]) / 360.0) - 0.5; + pitch = angles[PITCH]; + Com_Printf( "GBRTCW: damage location pitch = %f", pitch ); + if(pitch > -90) + pitch = pitch / 180.0; + else if(pitch <= -270 && pitch > -360) + pitch = (pitch + 360) / 180; + VectorCopy( client->ps.viewangles, viewangle ); + //If this doesn't work try (+ 360) instead of abs + //Com_Printf( "GBRTCW: viewangle yaw = %f", viewangle[YAW] ); + //Com_Printf( "GBRTCW: damage location yaw = %f", angles[YAW] ); + + + yaw = angles[YAW] - (viewangle[YAW] + 180.0f); + if(yaw < 0.0f) + yaw += 360.0f; + if(yaw > 360.0f) + yaw -= 360.0f; + + //AnglesToAxis( viewangle, wolfkick.axis ); + switch(client->lasthurt_mod) + { + case MOD_SHOTGUN: + trap_Vibrate(1000, 1, (count / 255.0) + 0.5f, "damage_shotgun", yaw, pitch); + break; + case MOD_GRENADE: + case MOD_GRENADE_SPLASH: + case MOD_GRENADE_LAUNCHER: + case MOD_GRENADE_PINEAPPLE: + trap_Vibrate(1000, 1, (count / 255.0) + 0.5f, "damage_frag", yaw, pitch); + break; + case MOD_ROCKET: + case MOD_ROCKET_SPLASH: + case MOD_ROCKET_LAUNCHER: + case MOD_PANZERFAUST: + case MOD_BFG: + case MOD_BFG_SPLASH: + case MOD_MORTAR: + case MOD_MORTAR_SPLASH: + trap_Vibrate(1000, 1, (count / 255.0) + 0.5f, "damage_rocket", yaw, pitch); + break; + case MOD_KNIFE: + case MOD_KNIFE2: + case MOD_KNIFE_STEALTH: + trap_Vibrate(1000, 1, (count / 255.0) + 0.5f, "damage_knife", yaw, pitch); + break; + case MOD_LUGER: + case MOD_COLT: + case MOD_SILENCER: + case MOD_AKIMBO: + case MOD_SPEARGUN_CO2: + case MOD_TARGET_LASER: + trap_Vibrate(1000, 1, (count / 255.0) + 0.5f, "damage_low_bullet", yaw, pitch); + break; + case MOD_THOMPSON: + case MOD_STEN: + case MOD_MAUSER: + case MOD_MP40: + case MOD_GARAND: + case MOD_SPEARGUN: + case MOD_CROSS: + trap_Vibrate(1000, 1, (count / 255.0) + 0.5f, "damage_mid_bullet", yaw, pitch); + break; + case MOD_RAILGUN: + case MOD_SNIPERRIFLE: + case MOD_SNOOPERSCOPE: + case MOD_FG42: + case MOD_FG42SCOPE: + case MOD_BAR: //----(SA) + case MOD_MACHINEGUN: + case MOD_VENOM: + case MOD_VENOM_FULL: + trap_Vibrate(1000, 1, (count / 255.0) + 0.5f, "damage_high_bullet", yaw, pitch); + break; + case MOD_FLAMETHROWER: + trap_Vibrate(1000, 1, (count / 255.0) + 0.5f, "damage_flamethrower", yaw, pitch); + break; + case MOD_LIGHTNING: + case MOD_TESLA: + case MOD_TELEFRAG: + case MOD_LOPER_HIT: + trap_Vibrate(1000, 1, (count / 255.0) + 0.5f, "damage_electric", yaw, pitch); + break; + case MOD_EXPLOSIVE: + case MOD_DYNAMITE: + case MOD_DYNAMITE_SPLASH: + case MOD_AIRSTRIKE: + trap_Vibrate(1000, 1, (count / 255.0) + 0.5f, "damage_explosion", yaw, pitch); + break; + case MOD_GAUNTLET: + case MOD_GRAPPLE: + case MOD_KICKED: + case MOD_GRABBER: + case MOD_LOPER_LEAP: + case MOD_LOPER_GROUND: + trap_Vibrate(1000, 1, (count / 255.0) + 0.5f, "damage_melee", yaw, pitch); + break; + case MOD_FALLING: + trap_Vibrate(1000, 1, (count / 255.0) + 0.5f, "damage_fall", yaw, pitch); + break; + case MOD_SUICIDE: + trap_Vibrate(1000, 1, (count / 255.0) + 0.5f, "damage_death", yaw, pitch); + break; + case MOD_POISONGAS: + case MOD_WATER: + trap_Vibrate(1000, 1, (count / 255.0) + 0.5f, "damage_gas", yaw, pitch); + break; + case MOD_ZOMBIESPIRIT: + case MOD_ZOMBIESPIRIT_SPLASH: + trap_Vibrate(1000, 1, (count / 255.0) + 0.5f, "damage_zombiespirit", yaw, pitch); + break; + case MOD_SLIME: + case MOD_ZOMBIESPIT: + case MOD_ZOMBIESPIT_SPLASH: + trap_Vibrate(1000, 1, (count / 255.0) + 0.5f, "damage_slime", yaw, pitch); + break; + case MOD_LAVA: + trap_Vibrate(1000, 1, (count / 255.0) + 0.5f, "damage_fire", yaw, pitch); + break; + case MOD_CRUSH: + case MOD_TRIGGER_HURT: + trap_Vibrate(1000, 1, (count / 255.0) + 0.5f, "damage_crush", yaw, pitch); + break; + + default: + trap_Vibrate(1000, 1, (count / 255.0) + 0.5f, "damage_mid_bullet", yaw, pitch); + break; + } + trap_Vibrate(1000, 0, (count / 255.0) + 0.5f, "ignore", 0.0, 0.0); } diff --git a/Projects/Android/jni/rtcw/src/game/g_alarm.c b/Projects/Android/jni/rtcw/src/game/g_alarm.c index 2a9df3d..a47f40f 100644 --- a/Projects/Android/jni/rtcw/src/game/g_alarm.c +++ b/Projects/Android/jni/rtcw/src/game/g_alarm.c @@ -163,6 +163,8 @@ void alarmbox_use( gentity_t *ent, gentity_t *other, gentity_t *foo ) { alarmbox_updateparts( ent, qtrue ); if ( other->client ) { G_AddEvent( ent, EV_GENERAL_SOUND, ent->soundPos3 ); + //TODO GB Add heartbeat + trap_Haptic(1, 0, 1.0f, "alarm_on", 0.0f, 0.0f); } // G_Printf("touched alarmbox\n"); @@ -183,6 +185,8 @@ void alarmbox_die( gentity_t *ent, gentity_t *inflictor, gentity_t *attacker, in ent->takedamage = qfalse; alarmbox_updateparts( ent, qtrue ); + trap_Haptic(1, 0, 1.0f, "end_alarm", 0.0f, 0.0f); + // fire 'death' targets if ( ent->targetdeath ) { t = NULL; diff --git a/Projects/Android/jni/rtcw/src/game/g_cmds.c b/Projects/Android/jni/rtcw/src/game/g_cmds.c index 5dfe7ad..1afaae6 100644 --- a/Projects/Android/jni/rtcw/src/game/g_cmds.c +++ b/Projects/Android/jni/rtcw/src/game/g_cmds.c @@ -1407,7 +1407,8 @@ void Cmd_Activate_f( gentity_t *ent ) { if ( ( ( Q_stricmp( traceEnt->classname, "func_door" ) == 0 ) || ( Q_stricmp( traceEnt->classname, "func_door_rotating" ) == 0 ) ) ) { //----(SA) modified - if ( walking ) { + //GB Force this on as they don't hve a key which seems unfair in VR + if ( walking || 1 == 1) { traceEnt->flags |= FL_SOFTACTIVATE; // no noise } G_TryDoor( traceEnt, ent, ent ); // (door,other,activator) @@ -1419,7 +1420,7 @@ void Cmd_Activate_f( gentity_t *ent ) { // Use_BinaryMover (traceEnt, ent, ent); // traceEnt->active = qtrue; } else if ( !Q_stricmp( traceEnt->classname, "func_invisible_user" ) ) { - if ( walking ) { + if ( walking || 1 == 1) { traceEnt->flags |= FL_SOFTACTIVATE; // no noise } traceEnt->use( traceEnt, ent, ent ); diff --git a/Projects/Android/jni/rtcw/src/game/g_combat.c b/Projects/Android/jni/rtcw/src/game/g_combat.c index 380b906..cfc89b9 100644 --- a/Projects/Android/jni/rtcw/src/game/g_combat.c +++ b/Projects/Android/jni/rtcw/src/game/g_combat.c @@ -359,8 +359,10 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int // if (self->client && self->client->hook) // Weapon_HookFree(self->client->hook); + trap_Haptic(1,0,1.0f,"player_dead",0,0); self->client->ps.pm_type = PM_DEAD; + if ( attacker ) { killer = attacker->s.number; if ( attacker->client ) { diff --git a/Projects/Android/jni/rtcw/src/game/g_items.c b/Projects/Android/jni/rtcw/src/game/g_items.c index 2b5143a..f2a91e2 100644 --- a/Projects/Android/jni/rtcw/src/game/g_items.c +++ b/Projects/Android/jni/rtcw/src/game/g_items.c @@ -39,7 +39,7 @@ If you have questions concerning this license or the applicable additional terms */ #include "g_local.h" - +#include "../../../RTCWVR/VrClientInfo.h" #define RESPAWN_SP -1 @@ -54,7 +54,7 @@ If you have questions concerning this license or the applicable additional terms #define RESPAWN_PARTIAL 998 // for multi-stage ammo/health #define RESPAWN_PARTIAL_DONE 999 // for multi-stage ammo/health - +extern vr_client_info_t* gVR; //====================================================================== int Pickup_Powerup( gentity_t *ent, gentity_t *other ) { @@ -87,6 +87,7 @@ int Pickup_Powerup( gentity_t *ent, gentity_t *other ) { // brandy also gives a little health (10) if ( ent->item->giTag == PW_NOFATIGUE ) { if ( Q_stricmp( ent->item->classname, "item_stamina_brandy" ) == 0 ) { + trap_Haptic(1, 0, 0.6, "give_drink", 0.0f, 0.0f); other->health += 10; if ( other->health > other->client->ps.stats[STAT_MAX_HEALTH] ) { other->health = other->client->ps.stats[STAT_MAX_HEALTH]; @@ -169,6 +170,7 @@ int Pickup_Powerup( gentity_t *ent, gentity_t *other ) { //====================================================================== int Pickup_Key( gentity_t *ent, gentity_t *other ) { other->client->ps.stats[STAT_KEYS] |= ( 1 << ent->item->giTag ); + trap_Haptic(1, gVR->right_handed ? 1 : 0, 1.0f, "pickup_item", 0.0f, 0.0f); if ( g_gametype.integer == GT_SINGLE_PLAYER ) { if ( !( ent->spawnflags & 8 ) ) { return RESPAWN_SP; @@ -187,6 +189,7 @@ Pickup_Clipboard */ int Pickup_Clipboard( gentity_t *ent, gentity_t *other ) { + trap_Haptic(1, gVR->right_handed ? 1 : 0, 1.0f, "pickup_item", 0.0f, 0.0f); if ( ent->spawnflags & 4 ) { return 0; // leave in world @@ -203,6 +206,7 @@ Pickup_Treasure int Pickup_Treasure( gentity_t *ent, gentity_t *other ) { gentity_t *player = AICast_FindEntityForName( "player" ); player->numTreasureFound++; + trap_Haptic(1, 0, 1.0, "pickup_treasure", 0.0f, 0.0f); G_SendMissionStats(); return RESPAWN_SP; // no respawn } @@ -218,6 +222,7 @@ void UseHoldableItem( gentity_t *ent, int item ) { switch ( item ) { case HI_WINE: // 1921 Chateu Lafite - gives 25 pts health up to max health ent->health += 25; + trap_Haptic(1, 0, 1.0, "give_drink", 0.0f, 0.0f); if ( ent->health > ent->client->ps.stats[STAT_MAX_HEALTH] ) { ent->health = ent->client->ps.stats[STAT_MAX_HEALTH]; } @@ -256,6 +261,7 @@ int Pickup_Holdable( gentity_t *ent, gentity_t *other ) { other->client->ps.holding = item->giTag; other->client->ps.stats[STAT_HOLDABLE_ITEM] |= ( 1 << ent->item->giTag ); //----(SA) added + trap_Haptic(1, gVR->right_handed ? 1 : 0, 1.0f, "pickup_item", 0.0f, 0.0f); if ( g_gametype.integer == GT_SINGLE_PLAYER ) { if ( !( ent->spawnflags & 8 ) ) { @@ -386,6 +392,7 @@ int Pickup_Ammo( gentity_t *ent, gentity_t *other ) { } Add_Ammo( other, ent->item->giTag, quantity, qfalse ); //----(SA) modified + trap_Haptic(1, gVR->right_handed ? 1 : 0, 1.0f, "pickup_item", 0.0f, 0.0f); // single player has no respawns (SA) if ( g_gametype.integer == GT_SINGLE_PLAYER ) { @@ -468,6 +475,7 @@ int Pickup_Weapon( gentity_t *ent, gentity_t *other ) { //----(SA) end Add_Ammo( other, weapon, quantity, !alreadyHave ); + trap_Haptic(1, gVR->right_handed ? 1 : 0, 1.0f, "pickup_item", 0.0f, 0.0f); //----(SA) no hook // if (weapon == WP_GRAPPLING_HOOK) @@ -498,6 +506,28 @@ int Pickup_Weapon( gentity_t *ent, gentity_t *other ) { int Pickup_Health( gentity_t *ent, gentity_t *other ) { int max; int quantity = 0; + float intensity = 1.0f; + //Trigger a haptic for armor pickup + intensity = ent->count / 100; + if(intensity < 0.4) + intensity = 0.4f; + + //Need to find food and see if different (cheese and other stuff) + //item_health / icons/iconh_med (25) + //item_health_wall / icons/iconh_wall (25) + //item_health_turkey / icons/iconh_turkey (15) + //item_health_breadandmeat / "icons/iconh_breadandmeat (10) + if(strstr(ent->item->classname,"turkey") || + strstr(ent->item->classname,"bread") || + strstr(ent->item->classname,"meat") || + strstr(ent->item->classname,"wine") || + strstr(ent->item->classname,"latour")) { + //quantity (25) + trap_Haptic(1, 0, intensity, "give_food", 0.0f, 0.0f); + } else { + trap_Haptic(1, 0, intensity, "give_health", 0.0f, 0.0f); + } + // small and mega healths will go over the max if ( ent->item->quantity != 5 && ent->item->quantity != 100 ) { @@ -548,6 +578,12 @@ int Pickup_Health( gentity_t *ent, gentity_t *other ) { //====================================================================== int Pickup_Armor( gentity_t *ent, gentity_t *other ) { + + //Trigger a haptic for armor pickup + if ( other->client->ps.stats[STAT_ARMOR] < 100 ) { + trap_Haptic(1,0,1.0f,"give_armor",0.0f, 0.0f); + } + other->client->ps.stats[STAT_ARMOR] += ent->item->quantity; // if ( other->client->ps.stats[STAT_ARMOR] > other->client->ps.stats[STAT_MAX_HEALTH] * 2 ) { // other->client->ps.stats[STAT_ARMOR] = other->client->ps.stats[STAT_MAX_HEALTH] * 2; diff --git a/Projects/Android/jni/rtcw/src/game/g_local.h b/Projects/Android/jni/rtcw/src/game/g_local.h index 9558694..008761d 100644 --- a/Projects/Android/jni/rtcw/src/game/g_local.h +++ b/Projects/Android/jni/rtcw/src/game/g_local.h @@ -1214,7 +1214,10 @@ void trap_GetUsercmd( int clientNum, usercmd_t *cmd ); qboolean trap_GetEntityToken( char *buffer, int bufferSize ); qboolean trap_GetTag( int clientNum, char *tagName, orientation_t * or ); -int trap_Vibrate(int duration, int channel, float intensity ); +//int trap_Vibrate(int duration, int channel, float intensity ); +int trap_Haptic( int duration, int channel, float intensity, char *description, float yaw, float height); +int trap_Vibrate( int duration, int channel, float intensity, char *description, float yaw, float height); +int trap_EnableHaptics(); int trap_DebugPolygonCreate( int color, int numPoints, vec3_t *points ); void trap_DebugPolygonDelete( int id ); diff --git a/Projects/Android/jni/rtcw/src/game/g_main.c b/Projects/Android/jni/rtcw/src/game/g_main.c index 6cfaffa..96f51f4 100644 --- a/Projects/Android/jni/rtcw/src/game/g_main.c +++ b/Projects/Android/jni/rtcw/src/game/g_main.c @@ -29,6 +29,7 @@ If you have questions concerning this license or the applicable additional terms +#include #include "g_local.h" #include "../../../RTCWVR/VrClientInfo.h" @@ -2413,7 +2414,7 @@ void G_RunFrame( int levelTime ) { int msec; //int start, end; - // if we are waiting for the level to restart, do nothing +// if we are waiting for the level to restart, do nothing if ( level.restarted ) { return; } diff --git a/Projects/Android/jni/rtcw/src/game/g_mover.c b/Projects/Android/jni/rtcw/src/game/g_mover.c index d4be299..a089f3c 100644 --- a/Projects/Android/jni/rtcw/src/game/g_mover.c +++ b/Projects/Android/jni/rtcw/src/game/g_mover.c @@ -35,6 +35,9 @@ If you have questions concerning this license or the applicable additional terms */ #include "g_local.h" +#include "../../../RTCWVR/VrClientInfo.h" + +extern vr_client_info_t* gVR; char *hintStrings[] = { "", // HINT_NONE @@ -769,13 +772,16 @@ void SetMoverState( gentity_t *ent, moverState_t moverState, int time ) { if ( kicked ) { f = 2000.0 / ent->gDuration; // double speed when kicked open ent->s.apos.trDuration = ent->gDuration / 2.0; + } else if ( soft ) { f = 500.0 / ent->gDuration; // 1/2 speed when soft opened ent->s.apos.trDuration = ent->gDuration * 2; + //trap_Vibrate(1, gVR->right_handed ? 0 : 1, 0.5f, "door_open", 0, 0); //I've reversed the hands as I presume you will open it with the hand your gun isn't in. } else { f = 1000.0 / ent->gDuration; // ent->s.apos.trDuration = ent->gDurationBack; // (SA) durationback? ent->s.apos.trDuration = ent->gDuration; + //trap_Vibrate(1, gVR->right_handed ? 0 : 1, 0.75f, "door_open", 0, 0); //not sure what this is } VectorScale( ent->rotate, f * ent->angle, ent->s.apos.trDelta ); ent->s.apos.trType = TR_LINEAR_STOP; @@ -1387,7 +1393,7 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator ) { if ( kicked ) { ent->teammaster->flags |= FL_KICKACTIVATE; } - if ( soft ) { + else if ( soft || 1 == 1) { ent->teammaster->flags |= FL_SOFTACTIVATE; } @@ -2200,17 +2206,21 @@ void G_TryDoor( gentity_t *ent, gentity_t *other, gentity_t *activator ) { Use_BinaryMover( ent->teammaster, activator, activator ); G_UseTargets( ent->teammaster, activator ); - } else + } + else { ent->active = qtrue; - if ( walking ) { + if ( walking || 1 == 1) { ent->flags |= FL_SOFTACTIVATE; // no noise + if(gVR) + trap_Vibrate(1, gVR->right_handed ? 0 : 1, 0.3f, "door_open", 0, 0); //I've reversed the hands as I presume you will open it with the hand your gun isn't in. } else { + if(gVR) + trap_Vibrate(1, gVR->right_handed ? 0 : 1, 0.5f, "door_open", 0, 0); //I've reversed the hands as I presume you will open it with the hand your gun isn't in. if ( activator ) { soundrange = HEAR_RANGE_DOOR_OPEN; } } - Use_BinaryMover( ent, activator, activator ); G_UseTargets( ent, activator ); } diff --git a/Projects/Android/jni/rtcw/src/game/g_public.h b/Projects/Android/jni/rtcw/src/game/g_public.h index f2d50dc..f0be592 100644 --- a/Projects/Android/jni/rtcw/src/game/g_public.h +++ b/Projects/Android/jni/rtcw/src/game/g_public.h @@ -250,6 +250,8 @@ typedef enum { G_GETTAG, G_HAPTIC, + G_HAPTICTRIGGER, + G_FULL_HAPTIC, BOTLIB_SETUP = 200, // ( void ); BOTLIB_SHUTDOWN, // ( void ); diff --git a/Projects/Android/jni/rtcw/src/game/g_syscalls.c b/Projects/Android/jni/rtcw/src/game/g_syscalls.c index 7924c69..ba351b3 100644 --- a/Projects/Android/jni/rtcw/src/game/g_syscalls.c +++ b/Projects/Android/jni/rtcw/src/game/g_syscalls.c @@ -255,8 +255,12 @@ qboolean trap_GetTag( int clientNum, char *tagName, orientation_t *or ) { return syscall( G_GETTAG, clientNum, tagName, or ); } -int trap_Vibrate(int duration, int channel, float intensity ) { - return syscall( G_HAPTIC, duration, channel, PASSFLOAT(intensity) ); +int trap_Vibrate( int duration, int channel, float intensity, char *description, float yaw, float height) { + return syscall( G_HAPTIC, duration, channel, PASSFLOAT(intensity), description, PASSFLOAT(yaw), PASSFLOAT(height)); +} + +int trap_Haptic( int duration, int channel, float intensity, char *description, float yaw, float height) { + return syscall( G_HAPTICTRIGGER, duration, channel, PASSFLOAT(intensity), description, PASSFLOAT(yaw), PASSFLOAT(height)); } // BotLib traps start here diff --git a/Projects/Android/jni/rtcw/src/game/g_weapon.c b/Projects/Android/jni/rtcw/src/game/g_weapon.c index 2a73b9f..144ce5d 100644 --- a/Projects/Android/jni/rtcw/src/game/g_weapon.c +++ b/Projects/Android/jni/rtcw/src/game/g_weapon.c @@ -141,7 +141,7 @@ void Weapon_Knife( gentity_t *ent ) { tent->s.weapon = ent->s.weapon; //we hit something - trap_Vibrate(100, gVR->right_handed ? 1 : 0, 0.9); + trap_Vibrate(100, gVR->right_handed ? 1 : 0, 0.9, "knife_hit", 0.0, 0.0); if ( tr.entityNum == ENTITYNUM_WORLD ) { // don't worry about doing any damage return; @@ -963,15 +963,17 @@ void Bullet_Fire( gentity_t *ent, float spread, int damage ) { if (!ent->aiCharacter) { qboolean right = gVR->right_handed; + // Allocates storage + char *fire_command = (char*)malloc(8 * sizeof(char)); + sprintf(fire_command, "fire_%i", ent->s.weapon); if (ent->s.weapon == WP_AKIMBO) { right = BG_AkimboFireSequence(ent->s.weapon, ent->client->ps.ammoclip[WP_AKIMBO], ent->client->ps.ammoclip[WP_COLT] ); - trap_Vibrate(100, right ? 1 : 0, 1.0); - + trap_Vibrate(100, right ? 1 : 0, 1.0, fire_command, 0.0, 0.0); } else{ - trap_Vibrate(100, right ? 1 : 0, 1.0); + trap_Vibrate(100, right ? 1 : 0, 1.0, fire_command, 0.0, 0.0); if (gVR->weapon_stabilised) { - trap_Vibrate(100, right ? 0 : 1, 0.7); + trap_Vibrate(100, right ? 0 : 1, 0.7, fire_command, 0.0, 0.0); } } } @@ -2033,9 +2035,9 @@ void FireWeapon( gentity_t *ent ) { ent->client->ps.classWeaponTime = level.time; // JPW NERVE Weapon_RocketLauncher_Fire( ent, aimSpreadScale ); if (!ent->aiCharacter) { - trap_Vibrate(200, gVR->right_handed ? 1 : 0, 1.0); + trap_Vibrate(200, gVR->right_handed ? 1 : 0, 1.0, "fire_rocket", 0.0, 0.0); if (gVR->weapon_stabilised) { - trap_Vibrate(200, gVR->right_handed ? 0 : 1, 0.7); + trap_Vibrate(200, gVR->right_handed ? 0 : 1, 0.7, "fire_rocket", 0.0, 0.0); } } break; diff --git a/Projects/Android/jni/rtcw/src/server/sv_game.c b/Projects/Android/jni/rtcw/src/server/sv_game.c index 951af6f..bb3acce 100644 --- a/Projects/Android/jni/rtcw/src/server/sv_game.c +++ b/Projects/Android/jni/rtcw/src/server/sv_game.c @@ -304,6 +304,13 @@ static int FloatAsInt( float f ) { } void RTCWVR_Vibrate(int duration, int channel, float intensity ); +void RTCWVR_Haptic(int duration, int channel, float intensity, char *description, float yaw, float height); +void RTCWVR_HapticEvent(const char* event, int position, int flags, int intensity, float angle, float yHeight ); +void RTCWVR_HapticUpdateEvent(const char* event, int intensity, float angle ); +void RTCWVR_HapticEndFrame(); +void RTCWVR_HapticStopEvent(const char* event); +void RTCWVR_HapticEnable(); +void RTCWVR_HapticDisable(); /* ==================== @@ -473,8 +480,12 @@ int SV_GameSystemCalls( int *args ) { return SV_GetTag( args[1], VMA( 2 ), VMA( 3 ) ); case G_HAPTIC: RTCWVR_Vibrate( args[1], args[2], VMF( 3 ) ); - return 0; + RTCWVR_Haptic( args[1], args[2], VMF( 3 ), VMA(4), VMF(5), VMF(6) ); + return 0; + case G_HAPTICTRIGGER: + RTCWVR_Haptic( args[1], args[2], VMF( 3 ), VMA(4), VMF(5), VMF(6) ); + return 0; //==================================== case BOTLIB_SETUP: diff --git a/Projects/Android/libs/haptic_service.aar b/Projects/Android/libs/haptic_service.aar new file mode 100644 index 0000000..9c2dfc7 Binary files /dev/null and b/Projects/Android/libs/haptic_service.aar differ diff --git a/java/com/drbeef/rtcwquest/GLES3JNIActivity.java b/java/com/drbeef/rtcwquest/GLES3JNIActivity.java index fbcf666..d470bec 100644 --- a/java/com/drbeef/rtcwquest/GLES3JNIActivity.java +++ b/java/com/drbeef/rtcwquest/GLES3JNIActivity.java @@ -14,17 +14,24 @@ 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 com.drbeef.externalhapticsservice.HapticServiceClient; + import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; @@ -38,7 +45,10 @@ import static android.system.Os.setenv; System.loadLibrary( "rtcw_client" ); } + private HapticServiceClient externalHapticsServiceClient = null; + private static final String TAG = "RTCWQuest"; + private static final String APPLICATION = "RTCWQuest"; private int permissionCount = 0; private static final int READ_EXTERNAL_STORAGE_PERMISSION_ID = 1; @@ -69,6 +79,84 @@ import static android.system.Os.setenv; System.exit(0); } + public void haptic_event(String event, int position, int flags, int intensity, float angle, float yHeight) { + + if (externalHapticsServiceClient.hasService()) { + try { + externalHapticsServiceClient.getHapticsService().hapticEvent(APPLICATION, event, position, flags, intensity, angle, yHeight); + } + catch (RemoteException r) + { + Log.v(APPLICATION, r.toString()); + } + } + } + + public void haptic_updateevent(String event, int intensity, float angle) { + + 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) { + + if (externalHapticsServiceClient.hasService()) { + try { + externalHapticsServiceClient.getHapticsService().hapticStopEvent(APPLICATION, event); + } + catch (RemoteException r) + { + Log.v(APPLICATION, r.toString()); + } + } + } + + public void haptic_endframe() { + + if (externalHapticsServiceClient.hasService()) { + try { + externalHapticsServiceClient.getHapticsService().hapticFrameTick(); + } + catch (RemoteException r) + { + Log.v(APPLICATION, r.toString()); + } + } + } + + public void haptic_enable() { + + if (externalHapticsServiceClient.hasService()) { + try { + externalHapticsServiceClient.getHapticsService().hapticEnable(); + } + catch (RemoteException r) + { + Log.v(APPLICATION, r.toString()); + } + } + } + + public void haptic_disable() { + + if (externalHapticsServiceClient.hasService()) { + try { + externalHapticsServiceClient.getHapticsService().hapticDisable(); + } + catch (RemoteException r) + { + Log.v(APPLICATION, r.toString()); + } + } + } + @Override protected void onCreate( Bundle icicle ) { Log.v( TAG, "----------------------------------------------------------------" ); @@ -212,6 +300,12 @@ import static android.system.Os.setenv; } + externalHapticsServiceClient = new HapticServiceClient(this, (state, desc) -> { + Log.v(APPLICATION, "ExternalHapticsService is:" + desc); + }); + + externalHapticsServiceClient.bindService(); + mNativeHandle = GLES3JNILib.onCreate( this, commandLineParams ); } @@ -262,7 +356,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() @@ -270,20 +367,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(); } @@ -296,7 +402,12 @@ import static android.system.Os.setenv; GLES3JNILib.onSurfaceDestroyed( mNativeHandle ); } - GLES3JNILib.onDestroy( mNativeHandle ); + if ( mNativeHandle != 0 ) + { + GLES3JNILib.onDestroy(mNativeHandle); + } + + externalHapticsServiceClient.stopBinding(); super.onDestroy(); // Reset everything in case the user re opens the app @@ -333,5 +444,4 @@ import static android.system.Os.setenv; mSurfaceHolder = null; } } - }