Skip to content

Commit

Permalink
BUG: Fix integration with updated Slicer event delegation and VTK Ope…
Browse files Browse the repository at this point in the history
…nVR API (#131)

* BUG: Fix integration with updated Slicer event delegation and VTK OpenVR API

Addressing issues highlighted in Slicer/Slicer@1cc3b2c62, this commit introduces
the `vtkVirtualRealityViewInteractorObserver` class. This addition streamlines
event delegation to MRML displayable managers and their associated widgets
by leveraging observation of the interactor style.

The modification enables the `vtkVirtualRealityViewInteractorStyle` to inherit
from `vtkOpenVRInteractorStyle`, eliminating the need for redundant code
implementation and duplication.

It also updates the use of `MapInputToAction()` to map "eventId to state"
following the VTK refactoring introduced in Kitware/VTK@b7f02e622 (update
openvr to action based input model).

Co-authored-by: Lucas Gandel <[email protected]>
Co-authored-by: Sankhesh Jhaveri <[email protected]>

* BUG: Restore handling of complex gesture and fix event processing

This commit revisits the invocation of `vtkMRMLViewInteractorStyle::ProcessEvents`
to prioritize event processing specific to `VirtualReality`. The additional
processing is now performed only if the events have not been processed already.

Furthermore, this commit restores the support for calling `OnStartGesture`
and `OnEndGesture`, which was inadvertently omitted in the previous commit
titled "BUG: Fix integration with updated Slicer event delegation and VTK
OpenVR API."

Co-authored-by: Sankhesh Jhaveri <[email protected]>

* BUG: Ensure passing of vtkEventData to displayable managers

This commit follows up to "BUG: Fix integration with updated Slicer event
delegation and VTK OpenVR API". It ensures that existing event data objects
are consistently passed down to the `Delegate` functions and associated
displayable managers.

* BUG: Ensure All Events are Processed through the VR CustomProcessEvents Callback

Following the previous commit titled "BUG: Ensure passing of vtkEventData to
displayable managers," this update guarantees the effective invocation of the
newly introduced custom delegation function, designed to handle a calldata
argument. This ensures that all processing is funneled through the
`vtkVirtualRealityViewInteractorObserver::CustomProcessEvents` callback. The
callback is responsible for handling 3D event data and passing it down appropriately.

---------

Co-authored-by: Lucas Gandel <[email protected]>
Co-authored-by: Sankhesh Jhaveri <[email protected]>
  • Loading branch information
3 people authored Dec 21, 2023
1 parent 53a9549 commit 22eba9f
Show file tree
Hide file tree
Showing 9 changed files with 571 additions and 302 deletions.
2 changes: 2 additions & 0 deletions VirtualReality/MRML/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ set(${KIT}_SRCS
vtkMRML${MODULE_NAME}LayoutNode.h
vtk${MODULE_NAME}ViewInteractor.cxx
vtk${MODULE_NAME}ViewInteractor.h
vtk${MODULE_NAME}ViewInteractorObserver.cxx
vtk${MODULE_NAME}ViewInteractorObserver.h
vtk${MODULE_NAME}ViewInteractorStyle.cxx
vtk${MODULE_NAME}ViewInteractorStyle.h
)
Expand Down
58 changes: 38 additions & 20 deletions VirtualReality/MRML/vtkVirtualRealityViewInteractor.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -195,18 +195,21 @@ void vtkVirtualRealityViewInteractor::SetTriggerButtonFunction(std::string funct
return;
}

// The "eventId to state" mapping (see call to `MapInputToAction` below) applies to right and left
// controller buttons because they are bound to the same eventId:
// - `vtk_openvr_binding_*.json` files define the "button to action" mapping
// - `vtkOpenVRInteractorStyle()` contructor defines the "action to eventId" mapping

if (functionId.empty())
{
vrInteractorStyle->MapInputToAction(vtkEventDataDevice::RightController, vtkEventDataDeviceInput::Trigger, VTKIS_NONE);
vrInteractorStyle->MapInputToAction(vtkEventDataDevice::LeftController, vtkEventDataDeviceInput::Trigger, VTKIS_NONE);
vrInteractorStyle->MapInputToAction(vtkCommand::Select3DEvent, VTKIS_NONE);

this->GestureEnabledButtons.clear();
this->GestureEnabledButtons.push_back(static_cast<int>(vtkEventDataDeviceInput::Grip));
}
else if (!functionId.compare(vtkVirtualRealityViewInteractor::GetButtonFunctionIdForGrabObjectsAndWorld()))
{
vrInteractorStyle->MapInputToAction(vtkEventDataDevice::RightController, vtkEventDataDeviceInput::Trigger, VTKIS_POSITION_PROP);
vrInteractorStyle->MapInputToAction(vtkEventDataDevice::LeftController, vtkEventDataDeviceInput::Trigger, VTKIS_POSITION_PROP);
vrInteractorStyle->MapInputToAction(vtkCommand::Select3DEvent, VTKIS_POSITION_PROP);

this->GestureEnabledButtons.clear();
this->GestureEnabledButtons.push_back(static_cast<int>(vtkEventDataDeviceInput::Grip));
Expand All @@ -227,10 +230,14 @@ void vtkVirtualRealityViewInteractor::SetGestureButtonToTrigger()
vtkWarningMacro("SetGestureButtonToTrigger: Current interactor style is not a VR interactor style");
return;
}
vrInteractorStyle->MapInputToAction(vtkEventDataDevice::RightController, vtkEventDataDeviceInput::Trigger, VTKIS_POSITION_PROP);
vrInteractorStyle->MapInputToAction(vtkEventDataDevice::LeftController, vtkEventDataDeviceInput::Trigger, VTKIS_POSITION_PROP);
vrInteractorStyle->MapInputToAction(vtkEventDataDevice::RightController, vtkEventDataDeviceInput::Grip, VTKIS_NONE);
vrInteractorStyle->MapInputToAction(vtkEventDataDevice::LeftController, vtkEventDataDeviceInput::Grip, VTKIS_NONE);

// The update "action to (eventId|function)" mapping (see call to `AddAction` below) applies to
// right and left controller buttons because they are bound to the same eventId:
// - "vtk_openvr_binding_*.json" defines the "button -> action" mapping
// - vtkOpenVRInteractorStyle defines the "action -> eventId" mapping
this->AddAction("/actions/vtk/in/TriggerAction", /*isAnalog=*/false,
[this](vtkEventData* ed) { this->HandleComplexGestureEvents(ed); });
this->AddAction("/actions/vtk/in/ComplexGestureAction", vtkCommand::Select3DEvent, /*isAnalog=*/false);

this->GestureEnabledButtons.clear();
this->GestureEnabledButtons.push_back(static_cast<int>(vtkEventDataDeviceInput::Trigger));
Expand All @@ -246,10 +253,13 @@ void vtkVirtualRealityViewInteractor::SetGestureButtonToGrip()
return;
}

vrInteractorStyle->MapInputToAction(vtkEventDataDevice::RightController, vtkEventDataDeviceInput::Trigger, VTKIS_NONE);
vrInteractorStyle->MapInputToAction(vtkEventDataDevice::LeftController, vtkEventDataDeviceInput::Trigger, VTKIS_NONE);
vrInteractorStyle->MapInputToAction(vtkEventDataDevice::RightController, vtkEventDataDeviceInput::Grip, VTKIS_POSITION_PROP);
vrInteractorStyle->MapInputToAction(vtkEventDataDevice::LeftController, vtkEventDataDeviceInput::Grip, VTKIS_POSITION_PROP);
// The update "action to (eventId|function)" mapping (see call to `AddAction` below) applies to
// right and left controller buttons because they are bound to the same eventId:
// - "vtk_openvr_binding_*.json" defines the "button -> action" mapping
// - vtkOpenVRInteractorStyle defines the "action -> eventId" mapping
this->AddAction("/actions/vtk/in/TriggerAction", vtkCommand::Select3DEvent, /*isAnalog=*/false);
this->AddAction("/actions/vtk/in/ComplexGestureAction", /*isAnalog=*/false,
[this](vtkEventData* ed) { this->HandleComplexGestureEvents(ed); });

this->GestureEnabledButtons.clear();
this->GestureEnabledButtons.push_back(static_cast<int>(vtkEventDataDeviceInput::Grip));
Expand All @@ -265,10 +275,14 @@ void vtkVirtualRealityViewInteractor::SetGestureButtonToTriggerAndGrip()
return;
}

vrInteractorStyle->MapInputToAction(vtkEventDataDevice::RightController, vtkEventDataDeviceInput::Trigger, VTKIS_POSITION_PROP);
vrInteractorStyle->MapInputToAction(vtkEventDataDevice::LeftController, vtkEventDataDeviceInput::Trigger, VTKIS_POSITION_PROP);
vrInteractorStyle->MapInputToAction(vtkEventDataDevice::RightController, vtkEventDataDeviceInput::Grip, VTKIS_POSITION_PROP);
vrInteractorStyle->MapInputToAction(vtkEventDataDevice::LeftController, vtkEventDataDeviceInput::Grip, VTKIS_POSITION_PROP);
// The update "action to (eventId|function)" mapping (see call to `AddAction` below) applies to
// right and left controller buttons because they are bound to the same eventId:
// - "vtk_openvr_binding_*.json" defines the "button -> action" mapping
// - vtkOpenVRInteractorStyle defines the "action -> eventId" mapping
this->AddAction("/actions/vtk/in/TriggerAction", /*isAnalog=*/false,
[this](vtkEventData* ed) { this->HandleComplexGestureEvents(ed); });
this->AddAction("/actions/vtk/in/ComplexGestureAction", /*isAnalog=*/false,
[this](vtkEventData* ed) { this->HandleComplexGestureEvents(ed); });

this->GestureEnabledButtons.clear();
this->GestureEnabledButtons.push_back(static_cast<int>(vtkEventDataDeviceInput::Grip));
Expand All @@ -285,10 +299,14 @@ void vtkVirtualRealityViewInteractor::SetGestureButtonToNone()
return;
}

vrInteractorStyle->MapInputToAction(vtkEventDataDevice::RightController, vtkEventDataDeviceInput::Trigger, VTKIS_NONE);
vrInteractorStyle->MapInputToAction(vtkEventDataDevice::LeftController, vtkEventDataDeviceInput::Trigger, VTKIS_NONE);
vrInteractorStyle->MapInputToAction(vtkEventDataDevice::RightController, vtkEventDataDeviceInput::Grip, VTKIS_NONE);
vrInteractorStyle->MapInputToAction(vtkEventDataDevice::LeftController, vtkEventDataDeviceInput::Grip, VTKIS_NONE);
// The update "action to (eventId|function)" mapping (see call to `AddAction` below) applies to
// right and left controller buttons because they are bound to the same eventId:
// - "vtk_openvr_binding_*.json" defines the "button -> action" mapping
// - vtkOpenVRInteractorStyle defines the "action -> eventId" mapping
this->AddAction("/actions/vtk/in/TriggerAction", /*isAnalog=*/false,
[](vtkEventData* vtkNotUsed(ed)) { });
this->AddAction("/actions/vtk/in/ComplexGestureAction", /*isAnalog=*/false,
[](vtkEventData* vtkNotUsed(ed)) { });

this->GestureEnabledButtons.clear();
}
Loading

0 comments on commit 22eba9f

Please sign in to comment.