openvr haptics
This commit is contained in:
@@ -135,6 +135,7 @@ pub struct InteractionState {
|
|||||||
pub hovered_id: Option<usize>,
|
pub hovered_id: Option<usize>,
|
||||||
pub release_actions: VecDeque<Box<dyn Fn()>>,
|
pub release_actions: VecDeque<Box<dyn Fn()>>,
|
||||||
pub next_push: Instant,
|
pub next_push: Instant,
|
||||||
|
pub haptics: Option<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for InteractionState {
|
impl Default for InteractionState {
|
||||||
@@ -146,6 +147,7 @@ impl Default for InteractionState {
|
|||||||
hovered_id: None,
|
hovered_id: None,
|
||||||
release_actions: VecDeque::new(),
|
release_actions: VecDeque::new(),
|
||||||
next_push: Instant::now(),
|
next_push: Instant::now(),
|
||||||
|
haptics: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -193,8 +195,14 @@ pub struct PointerHit {
|
|||||||
pub dist: f32,
|
pub dist: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Haptics {
|
||||||
|
pub intensity: f32,
|
||||||
|
pub duration: f32,
|
||||||
|
pub frequency: f32,
|
||||||
|
}
|
||||||
|
|
||||||
pub trait InteractionHandler {
|
pub trait InteractionHandler {
|
||||||
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit);
|
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> Option<Haptics>;
|
||||||
fn on_left(&mut self, app: &mut AppState, pointer: usize);
|
fn on_left(&mut self, app: &mut AppState, pointer: usize);
|
||||||
fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool);
|
fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool);
|
||||||
fn on_scroll(&mut self, app: &mut AppState, hit: &PointerHit, delta: f32);
|
fn on_scroll(&mut self, app: &mut AppState, hit: &PointerHit, delta: f32);
|
||||||
@@ -204,7 +212,9 @@ pub struct DummyInteractionHandler;
|
|||||||
|
|
||||||
impl InteractionHandler for DummyInteractionHandler {
|
impl InteractionHandler for DummyInteractionHandler {
|
||||||
fn on_left(&mut self, _app: &mut AppState, _pointer: usize) {}
|
fn on_left(&mut self, _app: &mut AppState, _pointer: usize) {}
|
||||||
fn on_hover(&mut self, _app: &mut AppState, _hit: &PointerHit) {}
|
fn on_hover(&mut self, _app: &mut AppState, _hit: &PointerHit) -> Option<Haptics> {
|
||||||
|
None
|
||||||
|
}
|
||||||
fn on_pointer(&mut self, _app: &mut AppState, _hit: &PointerHit, _pressed: bool) {}
|
fn on_pointer(&mut self, _app: &mut AppState, _hit: &PointerHit, _pressed: bool) {}
|
||||||
fn on_scroll(&mut self, _app: &mut AppState, _hit: &PointerHit, _delta: f32) {}
|
fn on_scroll(&mut self, _app: &mut AppState, _hit: &PointerHit, _delta: f32) {}
|
||||||
}
|
}
|
||||||
@@ -231,7 +241,10 @@ pub enum PointerMode {
|
|||||||
Middle,
|
Middle,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interact<O>(overlays: &mut OverlayContainer<O>, app: &mut AppState) -> [f32; 2]
|
pub fn interact<O>(
|
||||||
|
overlays: &mut OverlayContainer<O>,
|
||||||
|
app: &mut AppState,
|
||||||
|
) -> [(f32, Option<Haptics>); 2]
|
||||||
where
|
where
|
||||||
O: Default,
|
O: Default,
|
||||||
{
|
{
|
||||||
@@ -241,7 +254,11 @@ where
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn interact_hand<O>(idx: usize, overlays: &mut OverlayContainer<O>, app: &mut AppState) -> f32
|
fn interact_hand<O>(
|
||||||
|
idx: usize,
|
||||||
|
overlays: &mut OverlayContainer<O>,
|
||||||
|
app: &mut AppState,
|
||||||
|
) -> (f32, Option<Haptics>)
|
||||||
where
|
where
|
||||||
O: Default,
|
O: Default,
|
||||||
{
|
{
|
||||||
@@ -254,7 +271,7 @@ where
|
|||||||
log::warn!("Grabbed overlay {} does not exist", grab_data.grabbed_id);
|
log::warn!("Grabbed overlay {} does not exist", grab_data.grabbed_id);
|
||||||
pointer.interaction.grabbed = None;
|
pointer.interaction.grabbed = None;
|
||||||
}
|
}
|
||||||
return 0.1;
|
return (0.1, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(mut hit) = pointer.get_nearest_hit(overlays) else {
|
let Some(mut hit) = pointer.get_nearest_hit(overlays) else {
|
||||||
@@ -276,7 +293,7 @@ where
|
|||||||
clicked.backend.on_pointer(app, &hit, false);
|
clicked.backend.on_pointer(app, &hit, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0.0; // no hit
|
return (0.0, None); // no hit
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(hovered_id) = pointer.interaction.hovered_id {
|
if let Some(hovered_id) = pointer.interaction.hovered_id {
|
||||||
@@ -292,7 +309,7 @@ where
|
|||||||
}
|
}
|
||||||
let Some(hovered) = overlays.mut_by_id(hit.overlay) else {
|
let Some(hovered) = overlays.mut_by_id(hit.overlay) else {
|
||||||
log::warn!("Hit overlay {} does not exist", hit.overlay);
|
log::warn!("Hit overlay {} does not exist", hit.overlay);
|
||||||
return 0.0; // no hit
|
return (0.0, None); // no hit
|
||||||
};
|
};
|
||||||
|
|
||||||
pointer.interaction.hovered_id = Some(hit.overlay);
|
pointer.interaction.hovered_id = Some(hit.overlay);
|
||||||
@@ -312,10 +329,17 @@ where
|
|||||||
|
|
||||||
if pointer.now.grab && !pointer.before.grab && hovered.state.grabbable {
|
if pointer.now.grab && !pointer.before.grab && hovered.state.grabbable {
|
||||||
pointer.start_grab(hovered);
|
pointer.start_grab(hovered);
|
||||||
return hit.dist;
|
return (
|
||||||
|
hit.dist,
|
||||||
|
Some(Haptics {
|
||||||
|
intensity: 0.25,
|
||||||
|
duration: 0.1,
|
||||||
|
frequency: 0.1,
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
hovered.backend.on_hover(app, &hit);
|
let haptics = hovered.backend.on_hover(app, &hit);
|
||||||
pointer = &mut app.input_state.pointers[idx];
|
pointer = &mut app.input_state.pointers[idx];
|
||||||
|
|
||||||
if pointer.now.scroll.abs() > 0.1 {
|
if pointer.now.scroll.abs() > 0.1 {
|
||||||
@@ -336,7 +360,7 @@ where
|
|||||||
hovered.backend.on_pointer(app, &hit, false);
|
hovered.backend.on_pointer(app, &hit, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hit.dist
|
(hit.dist, haptics)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pointer {
|
impl Pointer {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use std::{array, io::Write, path::Path};
|
use std::{array, io::Write, path::Path, time::Duration};
|
||||||
|
|
||||||
use ovr_overlay::{
|
use ovr_overlay::{
|
||||||
input::{ActionHandle, ActionSetHandle, ActiveActionSet, InputManager, InputValueHandle},
|
input::{ActionHandle, ActionSetHandle, ActiveActionSet, InputManager, InputValueHandle},
|
||||||
@@ -11,7 +11,7 @@ use ovr_overlay::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::input::{TrackedDevice, TrackedDeviceRole},
|
backend::input::{Haptics, TrackedDevice, TrackedDeviceRole},
|
||||||
state::AppState,
|
state::AppState,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -119,6 +119,18 @@ impl OpenVrInputSource {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn haptics(&mut self, input: &mut InputManager, hand: usize, haptics: &Haptics) {
|
||||||
|
let hnd = self.hands[hand].haptics_hnd;
|
||||||
|
let _ = input.trigger_haptic_vibration_action(
|
||||||
|
hnd,
|
||||||
|
0.0,
|
||||||
|
Duration::from_secs_f32(haptics.duration),
|
||||||
|
haptics.frequency,
|
||||||
|
haptics.intensity,
|
||||||
|
INPUT_ANY,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn update(
|
pub fn update(
|
||||||
&mut self,
|
&mut self,
|
||||||
input: &mut InputManager,
|
input: &mut InputManager,
|
||||||
|
|||||||
@@ -162,8 +162,8 @@ pub fn openvr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
|
|||||||
|
|
||||||
space_mover.update(&mut chaperone_mgr, &mut overlays, &state);
|
space_mover.update(&mut chaperone_mgr, &mut overlays, &state);
|
||||||
|
|
||||||
let pointer_lengths = interact(&mut overlays, &mut state);
|
let lengths_haptics = interact(&mut overlays, &mut state);
|
||||||
for (idx, len) in pointer_lengths.iter().enumerate() {
|
for (idx, (len, haptics)) in lengths_haptics.iter().enumerate() {
|
||||||
lines.draw_from(
|
lines.draw_from(
|
||||||
pointer_lines[idx],
|
pointer_lines[idx],
|
||||||
state.input_state.pointers[idx].pose,
|
state.input_state.pointers[idx].pose,
|
||||||
@@ -171,6 +171,9 @@ pub fn openvr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
|
|||||||
state.input_state.pointers[idx].interaction.mode as usize + 1,
|
state.input_state.pointers[idx].interaction.mode as usize + 1,
|
||||||
&state.input_state.hmd,
|
&state.input_state.hmd,
|
||||||
);
|
);
|
||||||
|
if let Some(haptics) = haptics {
|
||||||
|
input_source.haptics(&mut input_mngr, idx, haptics)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lines.update(&mut overlay_mngr, &mut state);
|
lines.update(&mut overlay_mngr, &mut state);
|
||||||
|
|||||||
@@ -223,8 +223,8 @@ pub fn openxr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
|
|||||||
.iter_mut()
|
.iter_mut()
|
||||||
.for_each(|o| o.state.auto_movement(&mut app_state));
|
.for_each(|o| o.state.auto_movement(&mut app_state));
|
||||||
|
|
||||||
let pointer_lengths = interact(&mut overlays, &mut app_state);
|
let lengths_haptics = interact(&mut overlays, &mut app_state);
|
||||||
for (idx, len) in pointer_lengths.iter().enumerate() {
|
for (idx, (len, haptics)) in lengths_haptics.iter().enumerate() {
|
||||||
lines.draw_from(
|
lines.draw_from(
|
||||||
pointer_lines[idx],
|
pointer_lines[idx],
|
||||||
app_state.input_state.pointers[idx].pose,
|
app_state.input_state.pointers[idx].pose,
|
||||||
@@ -232,6 +232,9 @@ pub fn openxr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
|
|||||||
app_state.input_state.pointers[idx].interaction.mode as usize + 1,
|
app_state.input_state.pointers[idx].interaction.mode as usize + 1,
|
||||||
&app_state.input_state.hmd,
|
&app_state.input_state.hmd,
|
||||||
);
|
);
|
||||||
|
if let Some(haptics) = haptics {
|
||||||
|
//TODO!
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut layers = vec![];
|
let mut layers = vec![];
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use vulkano::image::view::ImageView;
|
|||||||
|
|
||||||
use crate::state::AppState;
|
use crate::state::AppState;
|
||||||
|
|
||||||
use super::input::{DummyInteractionHandler, InteractionHandler, PointerHit};
|
use super::input::{DummyInteractionHandler, Haptics, InteractionHandler, PointerHit};
|
||||||
|
|
||||||
static AUTO_INCREMENT: AtomicUsize = AtomicUsize::new(0);
|
static AUTO_INCREMENT: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
@@ -259,8 +259,8 @@ impl InteractionHandler for SplitOverlayBackend {
|
|||||||
fn on_left(&mut self, app: &mut AppState, pointer: usize) {
|
fn on_left(&mut self, app: &mut AppState, pointer: usize) {
|
||||||
self.interaction.on_left(app, pointer);
|
self.interaction.on_left(app, pointer);
|
||||||
}
|
}
|
||||||
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) {
|
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> Option<Haptics> {
|
||||||
self.interaction.on_hover(app, hit);
|
self.interaction.on_hover(app, hit)
|
||||||
}
|
}
|
||||||
fn on_scroll(&mut self, app: &mut AppState, hit: &PointerHit, delta: f32) {
|
fn on_scroll(&mut self, app: &mut AppState, hit: &PointerHit, delta: f32) {
|
||||||
self.interaction.on_scroll(app, hit, delta);
|
self.interaction.on_scroll(app, hit, delta);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use vulkano::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{
|
backend::{
|
||||||
input::{InteractionHandler, PointerHit, PointerMode},
|
input::{Haptics, InteractionHandler, PointerHit, PointerMode},
|
||||||
overlay::{OverlayBackend, OverlayRenderer},
|
overlay::{OverlayBackend, OverlayRenderer},
|
||||||
},
|
},
|
||||||
graphics::{WlxCommandBuffer, WlxGraphics, WlxPass, WlxPipeline, WlxPipelineLegacy},
|
graphics::{WlxCommandBuffer, WlxGraphics, WlxPass, WlxPipeline, WlxPipelineLegacy},
|
||||||
@@ -351,12 +351,22 @@ impl<D, S> InteractionHandler for Canvas<D, S> {
|
|||||||
fn on_left(&mut self, _app: &mut AppState, pointer: usize) {
|
fn on_left(&mut self, _app: &mut AppState, pointer: usize) {
|
||||||
self.hover_controls[pointer] = None;
|
self.hover_controls[pointer] = None;
|
||||||
}
|
}
|
||||||
fn on_hover(&mut self, _app: &mut AppState, hit: &PointerHit) {
|
fn on_hover(&mut self, _app: &mut AppState, hit: &PointerHit) -> Option<Haptics> {
|
||||||
|
let old = self.hover_controls[hit.pointer];
|
||||||
if let Some(i) = self.interactive_get_idx(hit.uv) {
|
if let Some(i) = self.interactive_get_idx(hit.uv) {
|
||||||
self.hover_controls[hit.pointer] = Some(i);
|
self.hover_controls[hit.pointer] = Some(i);
|
||||||
} else {
|
} else {
|
||||||
self.hover_controls[hit.pointer] = None;
|
self.hover_controls[hit.pointer] = None;
|
||||||
}
|
}
|
||||||
|
if old != self.hover_controls[hit.pointer] {
|
||||||
|
Some(Haptics {
|
||||||
|
intensity: 0.1,
|
||||||
|
duration: 0.01,
|
||||||
|
frequency: 5.0,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool) {
|
fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool) {
|
||||||
let idx = if pressed {
|
let idx = if pressed {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ use glam::{vec2, vec3a, Affine2, Quat, Vec2, Vec3};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{
|
backend::{
|
||||||
input::{InteractionHandler, PointerHit, PointerMode},
|
input::{Haptics, InteractionHandler, PointerHit, PointerMode},
|
||||||
overlay::{OverlayData, OverlayRenderer, OverlayState, SplitOverlayBackend},
|
overlay::{OverlayData, OverlayRenderer, OverlayState, SplitOverlayBackend},
|
||||||
},
|
},
|
||||||
config::def_pw_tokens,
|
config::def_pw_tokens,
|
||||||
@@ -73,13 +73,14 @@ impl ScreenInteractionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl InteractionHandler for ScreenInteractionHandler {
|
impl InteractionHandler for ScreenInteractionHandler {
|
||||||
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) {
|
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> Option<Haptics> {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
log::trace!("Hover: {:?}", hit.uv);
|
log::trace!("Hover: {:?}", hit.uv);
|
||||||
if self.next_move < Instant::now() {
|
if self.next_move < Instant::now() {
|
||||||
let pos = self.mouse_transform.transform_point2(hit.uv);
|
let pos = self.mouse_transform.transform_point2(hit.uv);
|
||||||
app.hid_provider.mouse_move(pos);
|
app.hid_provider.mouse_move(pos);
|
||||||
}
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool) {
|
fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool) {
|
||||||
let btn = match hit.mode {
|
let btn = match hit.mode {
|
||||||
|
|||||||
Reference in New Issue
Block a user