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

WebXR gamepad module support. #2521

Merged
merged 10 commits into from
Apr 22, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public static void vrPrefsWorkAround(Context aContext, Bundle aExtras) {
try (FileOutputStream out = new FileOutputStream(prefFileName)) {
out.write("pref(\"dom.vr.enabled\", true);\n".getBytes());
out.write("pref(\"dom.vr.external.enabled\", true);\n".getBytes());
out.write("pref(\"dom.vr.webxr.enabled\", true);\n".getBytes());
out.write("pref(\"webgl.enable-surface-texture\", true);\n".getBytes());
// Enable MultiView draft extension
out.write("pref(\"webgl.enable-draft-extensions\", true);\n".getBytes());
Expand Down
9 changes: 8 additions & 1 deletion app/src/main/cpp/BrowserWorld.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ BrowserWorld::State::CheckBackButton() {
(controller.buttonState & ControllerDelegate::BUTTON_APP)) {
VRBrowser::HandleBack();
} else if (webXRInterstialState == WebXRInterstialState::ALLOW_DISMISS
&& controller.lastButtonState == 0 && controller.buttonState) {
&& controller.lastButtonState && controller.buttonState == 0) {
VRBrowser::OnDismissWebXRInterstitial();
webXRInterstialState = WebXRInterstialState::HIDDEN;
}
Expand Down Expand Up @@ -581,6 +581,10 @@ BrowserWorld::State::ClearWebXRControllerData() {
};
controller.immersiveTouchedState = 0;
controller.immersivePressedState = 0;
controller.selectActionStartFrameId = 0;
controller.selectActionStopFrameId = 0;
controller.squeezeActionStartFrameId = 0;
controller.squeezeActionStopFrameId = 0;
for (int i = 0; i < controller.numAxes; ++i) {
controller.immersiveAxes[i] = 0;
}
Expand Down Expand Up @@ -948,6 +952,9 @@ BrowserWorld::StartFrame() {
m.context->Update();
m.externalVR->PullBrowserState();
m.externalVR->SetHapticState(m.controllers);

const uint64_t frameId = m.externalVR->GetFrameId();
m.controllers->SetFrameId(frameId);
m.CheckExitImmersive();

if (m.splashAnimation) {
Expand Down
15 changes: 15 additions & 0 deletions app/src/main/cpp/Controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ Controller::operator=(const Controller& aController) {
pointer = aController.pointer;
transformMatrix = aController.transformMatrix;
beamTransformMatrix = aController.beamTransformMatrix;
immersiveBeamTransform = aController.immersiveBeamTransform;
immersiveName = aController.immersiveName;
immersivePressedState = aController.immersivePressedState;
immersiveTouchedState = aController.immersiveTouchedState;
Expand All @@ -65,6 +66,13 @@ Controller::operator=(const Controller& aController) {
leftHanded = aController.leftHanded;
inDeadZone = aController.inDeadZone;
lastHoverEvent = aController.lastHoverEvent;
profile = aController.profile;
type = aController.type;
targetRayMode = aController.targetRayMode;
selectActionStartFrameId = aController.selectActionStartFrameId;
selectActionStopFrameId = aController.selectActionStopFrameId;
squeezeActionStartFrameId = aController.squeezeActionStartFrameId;
squeezeActionStopFrameId = aController.squeezeActionStopFrameId;
return *this;
}

Expand All @@ -88,6 +96,7 @@ Controller::Reset() {
pointer = nullptr;
transformMatrix = Matrix::Identity();
beamTransformMatrix = Matrix::Identity();
immersiveBeamTransform = Matrix::Identity();
immersiveName.clear();
immersivePressedState = 0;
immersiveTouchedState = 0;
Expand All @@ -102,6 +111,12 @@ Controller::Reset() {
leftHanded = false;
inDeadZone = true;
lastHoverEvent = 0.0;
type = device::UnknownType;
targetRayMode = device::TargetRayMode::TrackedPointer;
selectActionStartFrameId = 0;
selectActionStopFrameId = 0;
squeezeActionStartFrameId = 0;
squeezeActionStopFrameId = 0;
}

vrb::Vector Controller::StartPoint() const {
Expand Down
11 changes: 10 additions & 1 deletion app/src/main/cpp/Controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace crow {
class Pointer;
typedef std::shared_ptr<Pointer> PointerPtr;

static const int kControllerMaxButtonCount = 6;
static const int kControllerMaxButtonCount = 7;
static const int kControllerMaxAxes = 6;

struct Controller {
Expand Down Expand Up @@ -44,6 +44,7 @@ struct Controller {
PointerPtr pointer;
vrb::Matrix transformMatrix;
vrb::Matrix beamTransformMatrix;
vrb::Matrix immersiveBeamTransform;
std::string immersiveName;
uint64_t immersivePressedState;
uint64_t immersiveTouchedState;
Expand All @@ -52,6 +53,8 @@ struct Controller {
float immersiveAxes[kControllerMaxAxes];
uint32_t numAxes;
uint32_t numHaptics;
device::DeviceType type;
device::TargetRayMode targetRayMode;
float inputFrameID;
float pulseDuration;
float pulseIntensity;
Expand All @@ -61,6 +64,12 @@ struct Controller {
double lastHoverEvent;
device::CapabilityFlags deviceCapabilities;

std::string profile;
uint64_t selectActionStartFrameId;
uint64_t selectActionStopFrameId;
uint64_t squeezeActionStartFrameId;
uint64_t squeezeActionStopFrameId;

vrb::Vector StartPoint() const;
vrb::Vector Direction() const;

Expand Down
90 changes: 90 additions & 0 deletions app/src/main/cpp/ControllerContainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,16 @@ struct ControllerContainer::State {
bool visible = false;
vrb::Color pointerColor;
int gazeIndex = -1;
uint64_t immersiveFrameId;
uint64_t lastImmersiveFrameId;

void Initialize(vrb::CreationContextPtr& aContext) {
context = aContext;
root = Toggle::Create(aContext);
visible = true;
pointerColor = vrb::Color(1.0f, 1.0f, 1.0f, 1.0f);
immersiveFrameId = 0;
lastImmersiveFrameId = 0;
}

bool Contains(const int32_t aControllerIndex) {
Expand Down Expand Up @@ -194,6 +198,7 @@ ControllerContainer::CreateController(const int32_t aControllerIndex, const int3
controller.index = aControllerIndex;
controller.immersiveName = aImmersiveName;
controller.beamTransformMatrix = aBeamTransform;
controller.immersiveBeamTransform = aBeamTransform;
if (aModelIndex < 0) {
return;
}
Expand Down Expand Up @@ -234,6 +239,15 @@ ControllerContainer::CreateController(const int32_t aControllerIndex, const int3
m.updatePointerColor(controller);
}

void
ControllerContainer::SetImmersiveBeamTransform(const int32_t aControllerIndex,
const vrb::Matrix& aImmersiveBeamTransform) {
if (!m.Contains(aControllerIndex)) {
return;
}
m.list[aControllerIndex].immersiveBeamTransform = aImmersiveBeamTransform;
}

void
ControllerContainer::SetFocused(const int32_t aControllerIndex) {
if (!m.Contains(aControllerIndex)) {
Expand Down Expand Up @@ -287,6 +301,24 @@ ControllerContainer::SetVisible(const int32_t aControllerIndex, const bool aVisi
}
}

void
ControllerContainer::SetControllerType(const int32_t aControllerIndex, device::DeviceType aType) {
if (!m.Contains(aControllerIndex)) {
return;
}
Controller& controller = m.list[aControllerIndex];
controller.type = aType;
}

void
ControllerContainer::SetTargetRayMode(const int32_t aControllerIndex, device::TargetRayMode aMode) {
if (!m.Contains(aControllerIndex)) {
return;
}
Controller& controller = m.list[aControllerIndex];
controller.targetRayMode = aMode;
}

void
ControllerContainer::SetTransform(const int32_t aControllerIndex, const vrb::Matrix& aTransform) {
if (!m.Contains(aControllerIndex)) {
Expand Down Expand Up @@ -399,6 +431,54 @@ ControllerContainer::GetHapticFeedback(const int32_t aControllerIndex, uint64_t
aPulseIntensity = m.list[aControllerIndex].pulseIntensity;
}

void
ControllerContainer::SetSelectActionStart(const int32_t aControllerIndex) {
if (!m.Contains(aControllerIndex) || !m.immersiveFrameId) {
return;
}

if (m.list[aControllerIndex].selectActionStopFrameId >=
m.list[aControllerIndex].selectActionStartFrameId) {
m.list[aControllerIndex].selectActionStartFrameId = m.immersiveFrameId;
}
}

void
ControllerContainer::SetSelectActionStop(const int32_t aControllerIndex) {
if (!m.Contains(aControllerIndex) || !m.lastImmersiveFrameId) {
return;
}

if (m.list[aControllerIndex].selectActionStartFrameId >
m.list[aControllerIndex].selectActionStopFrameId) {
m.list[aControllerIndex].selectActionStopFrameId = m.lastImmersiveFrameId;
}
}

void
ControllerContainer::SetSqueezeActionStart(const int32_t aControllerIndex) {
if (!m.Contains(aControllerIndex) || !m.immersiveFrameId) {
return;
}

if (m.list[aControllerIndex].squeezeActionStopFrameId >=
m.list[aControllerIndex].squeezeActionStartFrameId) {
m.list[aControllerIndex].squeezeActionStartFrameId = m.immersiveFrameId;
}
}

void
ControllerContainer::SetSqueezeActionStop(const int32_t aControllerIndex) {
if (!m.Contains(aControllerIndex) || !m.lastImmersiveFrameId) {
return;
}

if (m.list[aControllerIndex].squeezeActionStartFrameId >
m.list[aControllerIndex].squeezeActionStopFrameId) {
m.list[aControllerIndex].squeezeActionStopFrameId = m.lastImmersiveFrameId;
}
}

void
ControllerContainer::SetLeftHanded(const int32_t aControllerIndex, const bool aLeftHanded) {
if (!m.Contains(aControllerIndex)) {
Expand Down Expand Up @@ -466,6 +546,16 @@ void ControllerContainer::SetGazeModeIndex(const int32_t aControllerIndex) {
m.gazeIndex = aControllerIndex;
}

void
ControllerContainer::SetFrameId(const uint64_t aFrameId) {
if (m.immersiveFrameId) {
m.lastImmersiveFrameId = aFrameId ? aFrameId : m.immersiveFrameId;
} else {
m.lastImmersiveFrameId = 0;
}
m.immersiveFrameId = aFrameId;
}

ControllerContainer::ControllerContainer(State& aState, vrb::CreationContextPtr& aContext) : m(aState) {
m.Initialize(aContext);
}
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/cpp/ControllerContainer.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,14 @@ class ControllerContainer : public crow::ControllerDelegate {
uint32_t GetControllerCount() override;
void CreateController(const int32_t aControllerIndex, const int32_t aModelIndex, const std::string& aImmersiveName) override;
void CreateController(const int32_t aControllerIndex, const int32_t aModelIndex, const std::string& aImmersiveName, const vrb::Matrix& aBeamTransform) override;
void SetImmersiveBeamTransform(const int32_t aControllerIndex, const vrb::Matrix& aImmersiveBeamTransform) override;
void SetFocused(const int32_t aControllerIndex) override;
void DestroyController(const int32_t aControllerIndex) override;
void SetCapabilityFlags(const int32_t aControllerIndex, const device::CapabilityFlags aFlags) override;
void SetEnabled(const int32_t aControllerIndex, const bool aEnabled) override;
void SetVisible(const int32_t aControllerIndex, const bool aVisible) override;
void SetControllerType(const int32_t aControllerIndex, device::DeviceType aType) override;
void SetTargetRayMode(const int32_t aControllerIndex, device::TargetRayMode aMode) override;
void SetTransform(const int32_t aControllerIndex, const vrb::Matrix& aTransform) override;
void SetButtonCount(const int32_t aControllerIndex, const uint32_t aNumButtons) override;
void SetButtonState(const int32_t aControllerIndex, const Button aWhichButton, const int32_t aImmersiveIndex, const bool aPressed, const bool aTouched, const float aImmersiveTrigger = -1.0f) override;
Expand All @@ -48,13 +51,18 @@ class ControllerContainer : public crow::ControllerDelegate {
uint32_t GetHapticCount(const int32_t aControllerIndex) override;
void SetHapticFeedback(const int32_t aControllerIndex, const uint64_t aInputFrameID, const float aPulseDuration, const float aPulseIntensity) override;
void GetHapticFeedback(const int32_t aControllerIndex, uint64_t &aInputFrameID, float& aPulseDuration, float& aPulseIntensity) override;
void SetSelectActionStart(const int32_t aControllerIndex) override;
void SetSelectActionStop(const int32_t aControllerIndex) override;
void SetSqueezeActionStart(const int32_t aControllerIndex) override;
void SetSqueezeActionStop(const int32_t aControllerIndex) override;
void SetLeftHanded(const int32_t aControllerIndex, const bool aLeftHanded) override;
void SetTouchPosition(const int32_t aControllerIndex, const float aTouchX, const float aTouchY) override;
void EndTouch(const int32_t aControllerIndex) override;
void SetScrolledDelta(const int32_t aControllerIndex, const float aScrollDeltaX, const float aScrollDeltaY) override;
void SetPointerColor(const vrb::Color& color) const;
void SetVisible(const bool aVisible);
void SetGazeModeIndex(const int32_t aControllerIndex) override;
void SetFrameId(const uint64_t aFrameId);
protected:
struct State;
ControllerContainer(State& aState, vrb::CreationContextPtr& aContext);
Expand Down
23 changes: 16 additions & 7 deletions app/src/main/cpp/ControllerDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "GestureDelegate.h"

#include <memory>
#include <string>

namespace crow {

Expand All @@ -22,23 +23,27 @@ class ControllerDelegate {
public:
enum Button {
BUTTON_TRIGGER = 1u << 0u,
BUTTON_TOUCHPAD = 1u << 1u,
BUTTON_APP = 1u << 2u,
BUTTON_A = 1u << 3u,
BUTTON_B = 1u << 4u,
BUTTON_X = 1u << 5u,
BUTTON_Y = 1u << 6u,
BUTTON_OTHERS = 1u << 7u, // Other buttons only for the immersive mode.
BUTTON_SQUEEZE = 1u << 1u,
BUTTON_TOUCHPAD = 1u << 2u,
BUTTON_APP = 1u << 3u,
BUTTON_A = 1u << 4u,
BUTTON_B = 1u << 5u,
BUTTON_X = 1u << 6u,
BUTTON_Y = 1u << 7u,
BUTTON_OTHERS = 1u << 8u, // Other buttons only for the immersive mode.
};

virtual void CreateController(const int32_t aControllerIndex, const int32_t aModelIndex, const std::string& aImmersiveName) = 0;
virtual void CreateController(const int32_t aControllerIndex, const int32_t aModelIndex, const std::string& aImmersiveName, const vrb::Matrix& aBeamTransform) = 0;
virtual void SetImmersiveBeamTransform(const int32_t aControllerIndex, const vrb::Matrix& aImmersiveBeamTransform) = 0;
virtual void SetFocused(const int32_t aControllerIndex) = 0;
virtual void DestroyController(const int32_t aControllerIndex) = 0;
virtual uint32_t GetControllerCount() = 0;
virtual void SetCapabilityFlags(const int32_t aControllerIndex, const device::CapabilityFlags aFlags) = 0;
virtual void SetEnabled(const int32_t aControllerIndex, const bool aEnabled) = 0;
virtual void SetVisible(const int32_t aControllerIndex, const bool aVisible) = 0;
virtual void SetControllerType(const int32_t aControllerIndex, device::DeviceType aType) = 0;
virtual void SetTargetRayMode(const int32_t aControllerIndex, device::TargetRayMode aMode) = 0;
virtual void SetTransform(const int32_t aControllerIndex, const vrb::Matrix& aTransform) = 0;
virtual void SetButtonCount(const int32_t aControllerIndex, const uint32_t aNumButtons) = 0;
virtual void SetButtonState(const int32_t aControllerIndex, const Button aWhichButton, const int32_t aImmersiveIndex, const bool aPressed, const bool aTouched, const float aImmersiveTrigger = -1.0f) = 0;
Expand All @@ -47,6 +52,10 @@ class ControllerDelegate {
virtual uint32_t GetHapticCount(const int32_t aControllerIndex) = 0;
virtual void SetHapticFeedback(const int32_t aControllerIndex, const uint64_t aInputFrameID, const float aPulseDuration, const float aPulseIntensity) = 0;
virtual void GetHapticFeedback(const int32_t aControllerIndex, uint64_t & aInputFrameID, float& aPulseDuration, float& aPulseIntensity) = 0;
virtual void SetSelectActionStart(const int32_t aControllerIndex) = 0;
virtual void SetSelectActionStop(const int32_t aControllerIndex) = 0;
virtual void SetSqueezeActionStart(const int32_t aControllerIndex) = 0;
virtual void SetSqueezeActionStop(const int32_t aControllerIndex) = 0;
virtual void SetLeftHanded(const int32_t aControllerIndex, const bool aLeftHanded) = 0;
virtual void SetTouchPosition(const int32_t aControllerIndex, const float aTouchX, const float aTouchY) = 0;
virtual void EndTouch(const int32_t aControllerIndex) = 0;
Expand Down
26 changes: 26 additions & 0 deletions app/src/main/cpp/Device.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const CapabilityFlags PositionEmulated = 1u << 9u;
const CapabilityFlags InlineSession = 1u << 10u;
const CapabilityFlags ImmersiveVRSession = 1u << 11u;
const CapabilityFlags ImmersiveARSession = 1u << 12u;
const CapabilityFlags GripSpacePosition = 1u << 13u;
enum class Eye { Left, Right };
enum class RenderMode { StandAlone, Immersive };
enum class CPULevel { Normal = 0, High };
Expand All @@ -32,6 +33,31 @@ typedef int32_t DeviceType;
const DeviceType UnknownType = 0;
const DeviceType OculusGo = 1;
const DeviceType OculusQuest = 2;
const DeviceType ViveFocus = 3;
const DeviceType ViveFocusPlus = 4;
const DeviceType PicoGaze = 5;
const DeviceType PicoNeo2 = 6;
const DeviceType PicoG2 = 7;

enum class TargetRayMode : uint8_t { Gaze, TrackedPointer, Screen };

// Placeholder buttons for WebXR
// https://www.w3.org/TR/webxr-gamepads-module-1/#xr-standard-gamepad-mapping
const uint8_t kImmersiveButtonTrigger = 0;
const uint8_t kImmersiveButtonSqueeze = 1;
const uint8_t kImmersiveButtonTouchpad = 2;
const uint8_t kImmersiveButtonThumbstick = 3;
const uint8_t kImmersiveButtonA = 4;
const uint8_t kImmersiveButtonB = 5;
const uint8_t kImmersiveButtonThumbrest = 6;

// Placeholder axes for WebXR
// https://www.w3.org/TR/webxr-gamepads-module-1/#xr-standard-gamepad-mapping
const uint8_t kImmersiveAxisTouchpadX = 0;
const uint8_t kImmersiveAxisTouchpadY = 1;
const uint8_t kImmersiveAxisThumbstickX = 2;
const uint8_t kImmersiveAxisThumbstickY = 3;

struct EyeRect {
float mX, mY;
float mWidth, mHeight;
Expand Down
Loading