relative positioning rework

This commit is contained in:
galister
2025-05-02 02:39:29 +09:00
parent 96a05d0835
commit fbb16eccf6
10 changed files with 177 additions and 106 deletions

View File

@@ -6,8 +6,9 @@ use glam::{Affine3A, Vec2, Vec3, Vec3A, Vec3Swizzles};
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
use crate::backend::common::{snap_upright, OverlaySelector}; use crate::backend::common::OverlaySelector;
use crate::config::{AStrMapExt, GeneralConfig}; use crate::backend::overlay::Positioning;
use crate::config::AStrMapExt;
use crate::overlays::anchor::ANCHOR_NAME; use crate::overlays::anchor::ANCHOR_NAME;
use crate::state::{AppSession, AppState, KeyboardFocus}; use crate::state::{AppSession, AppState, KeyboardFocus};
@@ -334,17 +335,10 @@ fn interact_hand<O>(
where where
O: Default, O: Default,
{ {
let hmd = app.input_state.hmd;
let mut pointer = &mut app.input_state.pointers[idx]; let mut pointer = &mut app.input_state.pointers[idx];
if let Some(grab_data) = pointer.interaction.grabbed { if let Some(grab_data) = pointer.interaction.grabbed {
if let Some(grabbed) = overlays.mut_by_id(grab_data.grabbed_id) { if let Some(grabbed) = overlays.mut_by_id(grab_data.grabbed_id) {
pointer.handle_grabbed( Pointer::handle_grabbed(idx, grabbed, app);
grabbed,
&hmd,
&app.anchor,
&mut app.tasks,
&mut app.session.config,
);
} else { } else {
log::warn!("Grabbed overlay {} does not exist", grab_data.grabbed_id.0); log::warn!("Grabbed overlay {} does not exist", grab_data.grabbed_id.0);
pointer.interaction.grabbed = None; pointer.interaction.grabbed = None;
@@ -537,6 +531,13 @@ impl Pointer {
old_curvature: overlay.state.curvature, old_curvature: overlay.state.curvature,
grab_all: matches!(self.interaction.mode, PointerMode::Right), grab_all: matches!(self.interaction.mode, PointerMode::Right),
}); });
overlay.state.positioning = match overlay.state.positioning {
Positioning::FollowHand { hand, lerp } => Positioning::FollowHandPaused { hand, lerp },
Positioning::FollowHead { lerp } => Positioning::FollowHeadPaused { lerp },
x => x,
};
// Show anchor
tasks.enqueue(TaskType::Overlay( tasks.enqueue(TaskType::Overlay(
OverlaySelector::Name(ANCHOR_NAME.clone()), OverlaySelector::Name(ANCHOR_NAME.clone()),
Box::new(|app, o| { Box::new(|app, o| {
@@ -553,25 +554,20 @@ impl Pointer {
log::info!("Hand {}: grabbed {}", self.idx, overlay.state.name); log::info!("Hand {}: grabbed {}", self.idx, overlay.state.name);
} }
fn handle_grabbed<O>( fn handle_grabbed<O>(idx: usize, overlay: &mut OverlayData<O>, app: &mut AppState)
&mut self, where
overlay: &mut OverlayData<O>,
hmd: &Affine3A,
anchor: &Affine3A,
tasks: &mut TaskContainer,
config: &mut GeneralConfig,
) where
O: Default, O: Default,
{ {
if self.now.grab { let mut pointer = &mut app.input_state.pointers[idx];
if let Some(grab_data) = self.interaction.grabbed.as_mut() { if pointer.now.grab {
if self.now.click { if let Some(grab_data) = pointer.interaction.grabbed.as_mut() {
self.interaction.mode = PointerMode::Special; if pointer.now.click {
pointer.interaction.mode = PointerMode::Special;
let cur_scale = overlay.state.transform.x_axis.length(); let cur_scale = overlay.state.transform.x_axis.length();
if cur_scale < 0.1 && self.now.scroll_y > 0.0 { if cur_scale < 0.1 && pointer.now.scroll_y > 0.0 {
return; return;
} }
if cur_scale > 20. && self.now.scroll_y < 0.0 { if cur_scale > 20. && pointer.now.scroll_y < 0.0 {
return; return;
} }
@@ -579,46 +575,62 @@ impl Pointer {
.state .state
.transform .transform
.matrix3 .matrix3
.mul_scalar(0.025f32.mul_add(-self.now.scroll_y, 1.0)); .mul_scalar(0.025f32.mul_add(-pointer.now.scroll_y, 1.0));
} else if config.allow_sliding && self.now.scroll_y.is_finite() { } else if app.session.config.allow_sliding && pointer.now.scroll_y.is_finite() {
grab_data.offset.z -= self.now.scroll_y * 0.05; grab_data.offset.z -= pointer.now.scroll_y * 0.05;
} }
overlay.state.transform.translation = self.pose.transform_point3a(grab_data.offset); overlay.state.transform.translation =
overlay.state.realign(hmd); pointer.pose.transform_point3a(grab_data.offset);
overlay.state.realign(&app.input_state.hmd);
overlay.state.dirty = true; overlay.state.dirty = true;
} else { } else {
log::error!("Grabbed overlay {} does not exist", overlay.state.id.0); log::error!("Grabbed overlay {} does not exist", overlay.state.id.0);
self.interaction.grabbed = None; pointer.interaction.grabbed = None;
} }
} else { } else {
if overlay.state.anchored { overlay.state.positioning = match overlay.state.positioning {
overlay.state.saved_transform = Positioning::FollowHandPaused { hand, lerp } => {
Some(snap_upright(*anchor, Vec3A::Y).inverse() * overlay.state.transform); Positioning::FollowHand { hand, lerp }
}
Positioning::FollowHeadPaused { lerp } => Positioning::FollowHead { lerp },
x => x,
};
if let Some(grab_data) = self.interaction.grabbed.as_ref() { let save_success = overlay.state.save_transform(app);
// re-borrow
pointer = &mut app.input_state.pointers[idx];
if save_success {
if let Some(grab_data) = pointer.interaction.grabbed.as_ref() {
if overlay.state.curvature != grab_data.old_curvature { if overlay.state.curvature != grab_data.old_curvature {
if let Some(val) = overlay.state.curvature { if let Some(val) = overlay.state.curvature {
config.curve_values.arc_set(overlay.state.name.clone(), val); app.session
.config
.curve_values
.arc_set(overlay.state.name.clone(), val);
} else { } else {
let ref_name = overlay.state.name.as_ref(); let ref_name = overlay.state.name.as_ref();
config.curve_values.arc_rm(ref_name); app.session.config.curve_values.arc_rm(ref_name);
} }
} }
} }
config.transform_values.arc_set( app.session.config.transform_values.arc_set(
overlay.state.name.clone(), overlay.state.name.clone(),
overlay.state.saved_transform.unwrap(), // safe overlay.state.saved_transform.unwrap(), // safe
); );
} }
self.interaction.grabbed = None; pointer.interaction.grabbed = None;
tasks.enqueue(TaskType::Overlay(
// Hide anchor
app.tasks.enqueue(TaskType::Overlay(
OverlaySelector::Name(ANCHOR_NAME.clone()), OverlaySelector::Name(ANCHOR_NAME.clone()),
Box::new(|_app, o| { Box::new(|_app, o| {
o.want_visible = false; o.want_visible = false;
}), }),
)); ));
log::info!("Hand {}: dropped {}", self.idx, overlay.state.name); log::info!("Hand {}: dropped {}", idx, overlay.state.name);
} }
} }

View File

@@ -17,7 +17,10 @@ use crate::{
state::{AppState, KeyboardFocus}, state::{AppState, KeyboardFocus},
}; };
use super::input::{DummyInteractionHandler, Haptics, InteractionHandler, PointerHit}; use super::{
common::snap_upright,
input::{DummyInteractionHandler, Haptics, InteractionHandler, PointerHit},
};
static OVERLAY_AUTO_INCREMENT: AtomicUsize = AtomicUsize::new(0); static OVERLAY_AUTO_INCREMENT: AtomicUsize = AtomicUsize::new(0);
@@ -44,7 +47,6 @@ pub struct OverlayState {
pub grabbable: bool, pub grabbable: bool,
pub interactable: bool, pub interactable: bool,
pub recenter: bool, pub recenter: bool,
pub anchored: bool,
pub keyboard_focus: Option<KeyboardFocus>, pub keyboard_focus: Option<KeyboardFocus>,
pub dirty: bool, pub dirty: bool,
pub alpha: f32, pub alpha: f32,
@@ -54,7 +56,7 @@ pub struct OverlayState {
pub spawn_point: Vec3A, pub spawn_point: Vec3A,
pub spawn_rotation: Quat, pub spawn_rotation: Quat,
pub saved_transform: Option<Affine3A>, pub saved_transform: Option<Affine3A>,
pub relative_to: RelativeTo, pub positioning: Positioning,
pub curvature: Option<f32>, pub curvature: Option<f32>,
pub interaction_transform: Affine2, pub interaction_transform: Affine2,
pub birthframe: usize, pub birthframe: usize,
@@ -70,12 +72,11 @@ impl Default for OverlayState {
grabbable: false, grabbable: false,
recenter: false, recenter: false,
interactable: false, interactable: false,
anchored: false,
keyboard_focus: None, keyboard_focus: None,
dirty: true, dirty: true,
alpha: 1.0, alpha: 1.0,
z_order: Z_ORDER_DEFAULT, z_order: Z_ORDER_DEFAULT,
relative_to: RelativeTo::None, positioning: Positioning::Floating,
curvature: None, curvature: None,
spawn_scale: 1.0, spawn_scale: 1.0,
spawn_point: Vec3A::NEG_Z, spawn_point: Vec3A::NEG_Z,
@@ -113,23 +114,6 @@ where
} }
impl OverlayState { impl OverlayState {
pub const fn parent_transform(&self, app: &AppState) -> Option<Affine3A> {
match self.relative_to {
RelativeTo::Head => Some(app.input_state.hmd),
RelativeTo::Hand(idx) => Some(app.input_state.pointers[idx].pose),
_ => None,
}
}
const fn get_anchor(&self, app: &AppState) -> Affine3A {
if self.anchored {
app.anchor
} else {
// fake anchor that's always in front of HMD
app.input_state.hmd
}
}
fn get_transform(&self) -> Affine3A { fn get_transform(&self) -> Affine3A {
self.saved_transform.unwrap_or_else(|| { self.saved_transform.unwrap_or_else(|| {
Affine3A::from_scale_rotation_translation( Affine3A::from_scale_rotation_translation(
@@ -141,21 +125,57 @@ impl OverlayState {
} }
pub fn auto_movement(&mut self, app: &mut AppState) { pub fn auto_movement(&mut self, app: &mut AppState) {
if let Some(parent) = self.parent_transform(app) { let (target_transform, lerp) = match self.positioning {
self.transform = parent * self.get_transform(); Positioning::FollowHead { lerp } => (app.input_state.hmd * self.get_transform(), lerp),
self.dirty = true; Positioning::FollowHand { hand, lerp } => (
} app.input_state.pointers[hand].pose * self.get_transform(),
lerp,
),
_ => return,
};
self.transform = match lerp {
1.0 => target_transform,
lerp => {
let scale = target_transform.matrix3.x_axis.length();
let rot_from = Quat::from_mat3a(&self.transform.matrix3.div_scalar(scale));
let rot_to = Quat::from_mat3a(&target_transform.matrix3.div_scalar(scale));
let rotation = rot_from.slerp(rot_to, lerp);
let translation = self
.transform
.translation
.slerp(target_transform.translation, lerp);
Affine3A::from_scale_rotation_translation(
Vec3::ONE * scale,
rotation,
translation.into(),
)
}
};
self.dirty = true;
} }
pub fn reset(&mut self, app: &mut AppState, hard_reset: bool) { pub fn reset(&mut self, app: &mut AppState, hard_reset: bool) {
let parent_transform = match self.positioning {
Positioning::Floating
| Positioning::FollowHead { .. }
| Positioning::FollowHeadPaused { .. } => app.input_state.hmd,
Positioning::FollowHand { hand, .. } | Positioning::FollowHandPaused { hand, .. } => {
app.input_state.pointers[hand].pose
}
Positioning::Anchored => app.anchor,
Positioning::Static => return,
};
if hard_reset { if hard_reset {
self.saved_transform = None; self.saved_transform = None;
} }
self.transform = self self.transform = parent_transform * self.get_transform();
.parent_transform(app)
.unwrap_or_else(|| self.get_anchor(app))
* self.get_transform();
if self.grabbable && hard_reset { if self.grabbable && hard_reset {
self.realign(&app.input_state.hmd); self.realign(&app.input_state.hmd);
@@ -163,6 +183,24 @@ impl OverlayState {
self.dirty = true; self.dirty = true;
} }
pub fn save_transform(&mut self, app: &mut AppState) -> bool {
let parent_transform = match self.positioning {
Positioning::Floating => snap_upright(app.input_state.hmd, Vec3A::Y),
Positioning::FollowHead { .. } | Positioning::FollowHeadPaused { .. } => {
app.input_state.hmd
}
Positioning::FollowHand { hand, .. } | Positioning::FollowHandPaused { hand, .. } => {
app.input_state.pointers[hand].pose
}
Positioning::Anchored => snap_upright(app.anchor, Vec3A::Y),
Positioning::Static => return false,
};
self.saved_transform = Some(parent_transform.inverse() * self.transform);
true
}
pub fn realign(&mut self, hmd: &Affine3A) { pub fn realign(&mut self, hmd: &Affine3A) {
let to_hmd = hmd.translation - self.transform.translation; let to_hmd = hmd.translation - self.transform.translation;
let up_dir: Vec3A; let up_dir: Vec3A;
@@ -218,7 +256,10 @@ where
.copied(); .copied();
} }
if matches!(self.state.relative_to, RelativeTo::None) { if matches!(
self.state.positioning,
Positioning::Floating | Positioning::Anchored
) {
let hard_reset; let hard_reset;
if let Some(transform) = app if let Some(transform) = app
.session .session
@@ -321,16 +362,22 @@ impl OverlayRenderer for FallbackRenderer {
// Boilerplate and dummies // Boilerplate and dummies
#[derive(Clone, Copy, Debug, Default)] #[derive(Clone, Copy, Debug, Default)]
pub enum RelativeTo { pub enum Positioning {
/// Stays in place unless rencentered /// Stays in place unless recentered, recenters relative to HMD
#[default] #[default]
None, Floating,
/// Stays in position relative to HMD /// Stays in place unless recentered, recenters relative to anchor
Head, Anchored,
/// Stays in position relative to hand /// Following HMD
Hand(usize), FollowHead { lerp: f32 },
/// Normally follows HMD, but paused due to interaction
FollowHeadPaused { lerp: f32 },
/// Following hand
FollowHand { hand: usize, lerp: f32 },
/// Normally follows hand, but paused due to interaction
FollowHandPaused { hand: usize, lerp: f32 },
/// Stays in place, no recentering /// Stays in place, no recentering
Stage, Static,
} }
pub struct SplitOverlayBackend { pub struct SplitOverlayBackend {

View File

@@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
backend::{ backend::{
overlay::RelativeTo, overlay::Positioning,
task::{TaskContainer, TaskType}, task::{TaskContainer, TaskType},
wayvr, wayvr,
}, },
@@ -33,13 +33,14 @@ pub enum AttachTo {
} }
impl AttachTo { impl AttachTo {
pub const fn get_relative_to(&self) -> RelativeTo { // TODO: adjustable lerp factor
pub const fn get_positioning(&self) -> Positioning {
match self { match self {
Self::None => RelativeTo::None, Self::None => Positioning::Floating,
Self::HandLeft => RelativeTo::Hand(0), Self::HandLeft => Positioning::FollowHand { hand: 0, lerp: 1.0 },
Self::HandRight => RelativeTo::Hand(1), Self::HandRight => Positioning::FollowHand { hand: 1, lerp: 1.0 },
Self::Stage => RelativeTo::Stage, Self::Stage => Positioning::Static,
Self::Head => RelativeTo::Head, Self::Head => Positioning::FollowHead { lerp: 1.0 },
} }
} }

View File

@@ -13,7 +13,7 @@ use crate::{
backend::{ backend::{
common::OverlaySelector, common::OverlaySelector,
input::PointerMode, input::PointerMode,
overlay::RelativeTo, overlay::Positioning,
task::{ColorChannel, SystemTask, TaskType}, task::{ColorChannel, SystemTask, TaskType},
}, },
config::{save_layout, save_settings, AStrSetExt}, config::{save_layout, save_settings, AStrSetExt},
@@ -626,15 +626,15 @@ fn run_watch(data: &WatchAction, app: &mut AppState) {
app.tasks.enqueue(TaskType::Overlay( app.tasks.enqueue(TaskType::Overlay(
OverlaySelector::Name(WATCH_NAME.into()), OverlaySelector::Name(WATCH_NAME.into()),
Box::new(|app, o| { Box::new(|app, o| {
if matches!(o.relative_to, RelativeTo::Hand(0)) { if matches!(o.positioning, Positioning::FollowHand { hand: 0, .. }) {
o.relative_to = RelativeTo::Hand(1); o.positioning = Positioning::FollowHand { hand: 1, lerp: 1.0 };
o.spawn_rotation = app.session.config.watch_rot o.spawn_rotation = app.session.config.watch_rot
* Quat::from_rotation_x(PI) * Quat::from_rotation_x(PI)
* Quat::from_rotation_z(PI); * Quat::from_rotation_z(PI);
o.spawn_point = app.session.config.watch_pos; o.spawn_point = app.session.config.watch_pos;
o.spawn_point.x *= -1.; o.spawn_point.x *= -1.;
} else { } else {
o.relative_to = RelativeTo::Hand(0); o.positioning = Positioning::FollowHand { hand: 0, lerp: 1.0 };
o.spawn_rotation = app.session.config.watch_rot; o.spawn_rotation = app.session.config.watch_rot;
o.spawn_point = app.session.config.watch_pos; o.spawn_point = app.session.config.watch_pos;
} }

View File

@@ -1,7 +1,7 @@
use glam::Vec3A; use glam::Vec3A;
use std::sync::{Arc, LazyLock}; use std::sync::{Arc, LazyLock};
use crate::backend::overlay::{OverlayData, OverlayState, RelativeTo, Z_ORDER_ANCHOR}; use crate::backend::overlay::{OverlayData, OverlayState, Positioning, Z_ORDER_ANCHOR};
use crate::config::{load_known_yaml, ConfigType}; use crate::config::{load_known_yaml, ConfigType};
use crate::gui::modular::{modular_canvas, ModularUiConfig}; use crate::gui::modular::{modular_canvas, ModularUiConfig};
use crate::state::AppState; use crate::state::AppState;
@@ -23,7 +23,7 @@ where
z_order: Z_ORDER_ANCHOR, z_order: Z_ORDER_ANCHOR,
spawn_scale: config.width, spawn_scale: config.width,
spawn_point: Vec3A::NEG_Z * 0.5, spawn_point: Vec3A::NEG_Z * 0.5,
relative_to: RelativeTo::Stage, positioning: Positioning::Static,
..Default::default() ..Default::default()
}, },
backend: Box::new(modular_canvas(config.size, &config.elements, state)?), backend: Box::new(modular_canvas(config.size, &config.elements, state)?),

View File

@@ -9,7 +9,8 @@ use crate::{
backend::{ backend::{
input::{InteractionHandler, PointerMode}, input::{InteractionHandler, PointerMode},
overlay::{ overlay::{
FrameMeta, OverlayBackend, OverlayData, OverlayRenderer, OverlayState, ShouldRender, FrameMeta, OverlayBackend, OverlayData, OverlayRenderer, OverlayState, Positioning,
ShouldRender,
}, },
}, },
config::{self, ConfigType}, config::{self, ConfigType},
@@ -222,7 +223,7 @@ where
name: KEYBOARD_NAME.into(), name: KEYBOARD_NAME.into(),
grabbable: true, grabbable: true,
recenter: true, recenter: true,
anchored: true, positioning: Positioning::Anchored,
interactable: true, interactable: true,
spawn_scale: width, spawn_scale: width,
spawn_point: vec3a(0., -0.5, 0.), spawn_point: vec3a(0., -0.5, 0.),

View File

@@ -50,7 +50,10 @@ use glam::{vec2, vec3a, Affine2, Affine3A, Quat, Vec2, Vec3};
use crate::{ use crate::{
backend::{ backend::{
input::{Haptics, InteractionHandler, PointerHit, PointerMode}, input::{Haptics, InteractionHandler, PointerHit, PointerMode},
overlay::{FrameMeta, OverlayRenderer, OverlayState, ShouldRender, SplitOverlayBackend}, overlay::{
FrameMeta, OverlayRenderer, OverlayState, Positioning, ShouldRender,
SplitOverlayBackend,
},
}, },
config::{def_pw_tokens, GeneralConfig, PwTokenMap}, config::{def_pw_tokens, GeneralConfig, PwTokenMap},
graphics::{fourcc_to_vk, CommandBuffers, WlxGraphics, WlxPipeline, WlxUploadsBuffer}, graphics::{fourcc_to_vk, CommandBuffers, WlxGraphics, WlxPipeline, WlxUploadsBuffer},
@@ -718,7 +721,7 @@ fn create_screen_state(
keyboard_focus: Some(KeyboardFocus::PhysicalScreen), keyboard_focus: Some(KeyboardFocus::PhysicalScreen),
grabbable: true, grabbable: true,
recenter: true, recenter: true,
anchored: true, positioning: Positioning::Anchored,
interactable: true, interactable: true,
spawn_scale: 1.5 * session.config.desktop_view_scale, spawn_scale: 1.5 * session.config.desktop_view_scale,
spawn_point: vec3a(0., 0.5, 0.), spawn_point: vec3a(0., 0.5, 0.),

View File

@@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
backend::{ backend::{
common::OverlaySelector, common::OverlaySelector,
overlay::{OverlayBackend, OverlayState, RelativeTo, Z_ORDER_TOAST}, overlay::{OverlayBackend, OverlayState, Positioning, Z_ORDER_TOAST},
task::TaskType, task::TaskType,
}, },
gui::{canvas::builder::CanvasBuilder, color_parse}, gui::{canvas::builder::CanvasBuilder, color_parse},
@@ -125,18 +125,22 @@ fn new_toast(toast: Toast, app: &mut AppState) -> Option<(OverlayState, Box<dyn
.copied() .copied()
.unwrap_or(DisplayMethod::Hide); .unwrap_or(DisplayMethod::Hide);
let (spawn_point, spawn_rotation, relative_to) = match current_method { let (spawn_point, spawn_rotation, positioning) = match current_method {
DisplayMethod::Hide => return None, DisplayMethod::Hide => return None,
DisplayMethod::Center => (vec3a(0., -0.2, -0.5), Quat::IDENTITY, RelativeTo::Head), DisplayMethod::Center => (
vec3a(0., -0.2, -0.5),
Quat::IDENTITY,
Positioning::FollowHead { lerp: 0.1 },
),
DisplayMethod::Watch => { DisplayMethod::Watch => {
let mut watch_pos = app.session.config.watch_pos + vec3a(-0.005, -0.05, 0.02); let mut watch_pos = app.session.config.watch_pos + vec3a(-0.005, -0.05, 0.02);
let mut watch_rot = app.session.config.watch_rot; let mut watch_rot = app.session.config.watch_rot;
let relative_to = match app.session.config.watch_hand { let relative_to = match app.session.config.watch_hand {
LeftRight::Left => RelativeTo::Hand(0), LeftRight::Left => Positioning::FollowHand { hand: 0, lerp: 1.0 },
LeftRight::Right => { LeftRight::Right => {
watch_pos.x = -watch_pos.x; watch_pos.x = -watch_pos.x;
watch_rot = watch_rot * Quat::from_rotation_x(PI) * Quat::from_rotation_z(PI); watch_rot = watch_rot * Quat::from_rotation_x(PI) * Quat::from_rotation_z(PI);
RelativeTo::Hand(1) Positioning::FollowHand { hand: 1, lerp: 1.0 }
} }
}; };
(watch_pos, watch_rot, relative_to) (watch_pos, watch_rot, relative_to)
@@ -202,7 +206,7 @@ fn new_toast(toast: Toast, app: &mut AppState) -> Option<(OverlayState, Box<dyn
spawn_rotation, spawn_rotation,
spawn_point, spawn_point,
z_order: Z_ORDER_TOAST, z_order: Z_ORDER_TOAST,
relative_to, positioning,
..Default::default() ..Default::default()
}; };
let backend = Box::new(canvas.build()); let backend = Box::new(canvas.build());

View File

@@ -1,7 +1,7 @@
use glam::Vec3A; use glam::Vec3A;
use crate::{ use crate::{
backend::overlay::{ui_transform, OverlayData, OverlayState, RelativeTo, Z_ORDER_WATCH}, backend::overlay::{ui_transform, OverlayData, OverlayState, Positioning, Z_ORDER_WATCH},
config::{load_known_yaml, ConfigType}, config::{load_known_yaml, ConfigType},
gui::{ gui::{
canvas::Canvas, canvas::Canvas,
@@ -18,7 +18,10 @@ where
{ {
let config = load_known_yaml::<ModularUiConfig>(ConfigType::Watch); let config = load_known_yaml::<ModularUiConfig>(ConfigType::Watch);
let relative_to = RelativeTo::Hand(state.session.config.watch_hand as usize); let positioning = Positioning::FollowHand {
hand: state.session.config.watch_hand as _,
lerp: 1.0,
};
Ok(OverlayData { Ok(OverlayData {
state: OverlayState { state: OverlayState {
@@ -30,7 +33,7 @@ where
spawn_point: state.session.config.watch_pos, spawn_point: state.session.config.watch_pos,
spawn_rotation: state.session.config.watch_rot, spawn_rotation: state.session.config.watch_rot,
interaction_transform: ui_transform(config.size), interaction_transform: ui_transform(config.size),
relative_to, positioning,
..Default::default() ..Default::default()
}, },
backend: Box::new(create_watch_canvas(Some(config), state)?), backend: Box::new(create_watch_canvas(Some(config), state)?),

View File

@@ -402,7 +402,7 @@ where
.insert(disp_handle, overlay.state.id); .insert(disp_handle, overlay.state.id);
if let Some(attach_to) = &conf_display.attach_to { if let Some(attach_to) = &conf_display.attach_to {
overlay.state.relative_to = attach_to.get_relative_to(); overlay.state.positioning = attach_to.get_positioning();
} }
if let Some(rot) = &conf_display.rotation { if let Some(rot) = &conf_display.rotation {