Skip to content
This repository has been archived by the owner on Jul 22, 2024. It is now read-only.

Commit

Permalink
Add support for haptic feedback on Pico controllers (#2932)
Browse files Browse the repository at this point in the history
* Add support for haptic feedback on Pico controllers

* Swap which contoller vibrates.

Co-authored-by: Randall E. Barker <[email protected]>
  • Loading branch information
MortimerGoro and bluemarvin authored Mar 9, 2020
1 parent fcec46e commit 25bc08b
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 2 deletions.
1 change: 1 addition & 0 deletions app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ target_sources(
PUBLIC
src/picovr/cpp/native-lib.cpp
src/picovr/cpp/DeviceDelegatePicoVR.cpp
src/picovr/cpp/VRBrowserPico.cpp
)
elseif(NOAPI)
target_sources(
Expand Down
23 changes: 21 additions & 2 deletions app/src/picovr/cpp/DeviceDelegatePicoVR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

#include "DeviceDelegatePicoVR.h"
#include "ElbowModel.h"
#include "BrowserEGLContext.h"
#include "VRBrowserPico.h"

#include <EGL/egl.h>
#include "vrb/CameraEye.h"
Expand Down Expand Up @@ -53,6 +53,7 @@ struct DeviceDelegatePicoVR::State {
float axisX = 0;
float axisY = 0;
ElbowModel::HandEnum hand;
int hapticFrameID = 0;
Controller()
: index(-1)
, created(false)
Expand Down Expand Up @@ -142,6 +143,16 @@ struct DeviceDelegatePicoVR::State {
}
}

void UpdateHaptics(Controller& aController) {
uint64_t inputFrameID = 0;
float pulseDuration = 0.0f, pulseIntensity = 0.0f;
controllerDelegate->GetHapticFeedback(aController.index, inputFrameID, pulseDuration, pulseIntensity);

if (aController.hapticFrameID != inputFrameID) {
VRBrowserPico::UpdateHaptics(aController.index, pulseIntensity, pulseDuration);
}
}

void UpdateControllers() {
for (int32_t i = 0; i < controllers.size(); ++i) {
if (!controllers[i].enabled) {
Expand Down Expand Up @@ -208,6 +219,10 @@ struct DeviceDelegatePicoVR::State {
}

controllerDelegate->SetTransform(i, transform);

if (controllerDelegate->GetHapticCount(i)) {
UpdateHaptics(controllers[i]);
}
}
}
};
Expand All @@ -227,6 +242,10 @@ DeviceDelegatePicoVR::SetRenderMode(const device::RenderMode aMode) {
return;
}
m.renderMode = aMode;
if (aMode == device::RenderMode::StandAlone) {
// Ensure that all haptics are cancelled when exiting WebVR
VRBrowserPico::CancelAllHaptics();
}
}

device::RenderMode
Expand Down Expand Up @@ -296,7 +315,7 @@ DeviceDelegatePicoVR::SetControllerDelegate(ControllerDelegatePtr& aController)
beam.TranslateInPlace(vrb::Vector(0.0f, 0.012f, -0.06f));
m.controllerDelegate->CreateController(index, int32_t(controller.hand), controller.IsRightHand() ? "Pico Neo 2 (Right)" : "Pico Neo 2 (LEFT)", beam);
m.controllerDelegate->SetButtonCount(index, kNumButtons);
m.controllerDelegate->SetHapticCount(index, 0);
m.controllerDelegate->SetHapticCount(index, 1);
} else {
vrb::Matrix beam = vrb::Matrix::Rotation(vrb::Vector(1.0f, 0.0f, 0.0f), -vrb::PI_FLOAT / 11.5f);

Expand Down
76 changes: 76 additions & 0 deletions app/src/picovr/cpp/VRBrowserPico.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "VRBrowserPico.h"
#include "vrb/ConcreteClass.h"
#include "vrb/Logger.h"
#include "JNIUtil.h"

namespace {

const char* sUpdateHapticsName = "updateHaptics";
const char* sUpdateHapticsSignature = "(IFF)V";
const char* sCancelAllHapticsName = "cancelAllHaptics";
const char* sCancelAllHapticsSignature = "()V";

JNIEnv* sEnv = nullptr;
jclass sBrowserClass = nullptr;
jobject sActivity = nullptr;
jmethodID sUpdateHaptics = nullptr;
jmethodID sCancelAllHaptics = nullptr;
}

namespace crow {

void
VRBrowserPico::InitializeJava(JNIEnv* aEnv, jobject aActivity) {
if (aEnv == sEnv) {
return;
}
sEnv = aEnv;
if (!sEnv) {
return;
}
sActivity = sEnv->NewGlobalRef(aActivity);
sBrowserClass = sEnv->GetObjectClass(sActivity);
if (!sBrowserClass) {
return;
}

sUpdateHaptics = FindJNIMethodID(sEnv, sBrowserClass, sUpdateHapticsName, sUpdateHapticsSignature);
sCancelAllHaptics = FindJNIMethodID(sEnv, sBrowserClass, sCancelAllHapticsName, sCancelAllHapticsSignature);
}

void
VRBrowserPico::ShutdownJava() {
if (!sEnv) {
return;
}
if (sActivity) {
sEnv->DeleteGlobalRef(sActivity);
sActivity = nullptr;
}

sBrowserClass = nullptr;
sUpdateHaptics = nullptr;
sCancelAllHaptics = nullptr;
sEnv = nullptr;
}


void
VRBrowserPico::UpdateHaptics(jint aControllerIndex, jfloat aIntensity, jfloat aDuration) {
if (!ValidateMethodID(sEnv, sActivity, sUpdateHaptics, __FUNCTION__)) { return; }
sEnv->CallVoidMethod(sActivity, sUpdateHaptics, aControllerIndex, aIntensity, aDuration);
CheckJNIException(sEnv, __FUNCTION__);
}
void
VRBrowserPico::CancelAllHaptics() {
if (!ValidateMethodID(sEnv, sActivity, sCancelAllHaptics, __FUNCTION__)) { return; }
sEnv->CallVoidMethod(sActivity, sCancelAllHaptics);
CheckJNIException(sEnv, __FUNCTION__);
}

} // namespace crow
23 changes: 23 additions & 0 deletions app/src/picovr/cpp/VRBrowserPico.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#pragma once
#include "vrb/MacroUtils.h"

#include <memory>
#include <string>
#include <jni.h>
#include <functional>

namespace crow {

namespace VRBrowserPico {
void InitializeJava(JNIEnv* aEnv, jobject aActivity);
void ShutdownJava();
void UpdateHaptics(jint aControllerIndex, jfloat aIntensity, jfloat aDuration);
void CancelAllHaptics();
} // namespace VRBrowser;

} // namespace crow
3 changes: 3 additions & 0 deletions app/src/picovr/cpp/native-lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "BrowserWorld.h"
#include "DeviceDelegatePicoVR.h"
#include "VRBrowserPico.h"
#include "vrb/GLError.h"
#include "vrb/Logger.h"
#include "vrb/RunnableQueue.h"
Expand Down Expand Up @@ -36,6 +37,7 @@ JNI_METHOD(void, nativeInitialize)
(JNIEnv* aEnv, jobject aActivity, jint width, jint height, jobject aAssetManager, jint type, jint focusInex) {
gDestroyed = false;
sQueue->AttachToThread();
VRBrowserPico::InitializeJava(aEnv, aActivity);
if (!sDevice) {
sDevice = crow::DeviceDelegatePicoVR::Create(BrowserWorld::Instance().GetRenderContext());
}
Expand All @@ -61,6 +63,7 @@ JNI_METHOD(void, nativeDestroy)
BrowserWorld::Instance().RegisterDeviceDelegate(nullptr);
sDevice = nullptr;
BrowserWorld::Destroy();
VRBrowserPico::ShutdownJava();
}

JNI_METHOD(void, nativePause)
Expand Down
27 changes: 27 additions & 0 deletions app/src/picovr/java/org/mozilla/vrbrowser/PlatformActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import android.os.Bundle;
import android.util.Log;

import androidx.annotation.Keep;
import androidx.annotation.NonNull;

import com.picovr.client.HbListener;
Expand Down Expand Up @@ -97,6 +98,7 @@ public void onBindService() {
@Override
protected void onPause() {
if (mControllerManager != null) {
cancelAllHaptics();
mControllerManager.unbindService();
} else if (mHbManager != null) {
mHbManager.Pause();
Expand Down Expand Up @@ -315,6 +317,31 @@ public void onChannelChanged(int i, int i1) {

}

// Called by native
@Keep
@SuppressWarnings("unused")
private void updateHaptics(int aControllerIndex, float aIntensity, float aDurationSeconds) {
runOnUiThread(() -> {
if (mControllerManager != null) {
float intensity = 255.0f * Math.max(Math.min(aIntensity, 1.0f), 0.0f);
int durationMs = Math.round(aDurationSeconds * 1000);
ControllerClient.vibrateCV2ControllerStrength(intensity, durationMs, 1 - aControllerIndex);
}
});
}

// Called by native
@Keep
@SuppressWarnings("unused")
private void cancelAllHaptics() {
runOnUiThread(() -> {
if (mControllerManager != null) {
ControllerClient.vibrateCV2ControllerStrength(0, 0, 0);
ControllerClient.vibrateCV2ControllerStrength(0, 0, 1);
}
});
}

protected native void nativeOnCreate();
protected native void nativeInitialize(int width, int height, Object aAssetManager, int type, int focusIndex);
protected native void nativeShutdown();
Expand Down

0 comments on commit 25bc08b

Please sign in to comment.