diff --git a/src/backend/common.rs b/src/backend/common.rs index 885d4d3..1151390 100644 --- a/src/backend/common.rs +++ b/src/backend/common.rs @@ -46,7 +46,7 @@ where }; let mut watch = create_watch::(&app, &screens); - watch.state.want_visible = false; + watch.state.want_visible = true; overlays.insert(watch.state.id, watch); let mut keyboard = create_keyboard(&app); diff --git a/src/backend/input.rs b/src/backend/input.rs index 65a29e5..ec30c07 100644 --- a/src/backend/input.rs +++ b/src/backend/input.rs @@ -424,7 +424,7 @@ impl Pointer { overlay.state.realign(hmd); overlay.state.dirty = true; } else { - overlay.state.spawn_point = overlay.state.transform.translation; + overlay.state.spawn_point = overlay.state.transform.translation.into(); self.interaction.grabbed = None; log::info!("Hand {}: dropped {}", self.idx, overlay.state.name); } diff --git a/src/backend/openvr/lines.rs b/src/backend/openvr/lines.rs index f7373b4..eb9e462 100644 --- a/src/backend/openvr/lines.rs +++ b/src/backend/openvr/lines.rs @@ -21,6 +21,7 @@ static AUTO_INCREMENT: AtomicUsize = AtomicUsize::new(1); pub(super) struct LinePool { lines: IdMap>, view: Arc, + colors: [Vec4; 4], } impl LinePool { @@ -46,6 +47,12 @@ impl LinePool { LinePool { lines: IdMap::new(), view, + colors: [ + Vec4::new(1., 1., 1., 1.), + Vec4::new(0., 0.375, 0.5, 1.), + Vec4::new(0.69, 0.188, 0., 1.), + Vec4::new(0.375, 0., 0.5, 1.), + ], } } @@ -56,7 +63,7 @@ impl LinePool { state: OverlayState { name: Arc::from(format!("wlx-line{}", id)), show_hide: true, - width: 0.002, + spawn_scale: 0.002, size: (0, 0), ..Default::default() }, @@ -77,13 +84,15 @@ impl LinePool { id } - pub fn draw_from(&mut self, id: usize, mut from: Affine3A, len: f32, color: Vec4) { + pub fn draw_from(&mut self, id: usize, mut from: Affine3A, len: f32, color: usize) { let rotation = Affine3A::from_axis_angle(Vec3::X, -PI * 0.5); from.translation = from.translation + from.transform_vector3a(Vec3A::NEG_Z) * (len * 0.5); let transform = from * rotation * Affine3A::from_scale(Vec3::new(1., len / 0.002, 1.)); - self.draw_transform(id, transform, color); + debug_assert!(color < self.colors.len()); + + self.draw_transform(id, transform, self.colors[color]); } fn draw_transform(&mut self, id: usize, transform: Affine3A, color: Vec4) { diff --git a/src/backend/openvr/mod.rs b/src/backend/openvr/mod.rs index 1db4f42..2dac613 100644 --- a/src/backend/openvr/mod.rs +++ b/src/backend/openvr/mod.rs @@ -1,4 +1,3 @@ -use glam::Vec4; use std::{ collections::VecDeque, sync::{ @@ -143,13 +142,17 @@ pub fn openvr_run(running: Arc) -> Result<(), BackendError> { input_source.update(&mut input_mngr, &mut system_mngr, &mut state); state.input_state.post_update(); + overlays + .iter_mut() + .for_each(|o| o.state.auto_movement(&mut state)); + let pointer_lengths = interact(&mut overlays, &mut state); for (idx, len) in pointer_lengths.iter().enumerate() { lines.draw_from( pointer_lines[idx], state.input_state.pointers[idx].pose, *len, - Vec4::ONE, + state.input_state.pointers[idx].interaction.mode as usize + 1, ); } diff --git a/src/backend/openvr/overlay.rs b/src/backend/openvr/overlay.rs index afadf8c..5dfe37d 100644 --- a/src/backend/openvr/overlay.rs +++ b/src/backend/openvr/overlay.rs @@ -12,6 +12,8 @@ use crate::{ state::AppState, }; +const WIDTH: f32 = 1.0; + #[derive(Default)] pub(super) struct OpenVrOverlayData { handle: Option, @@ -118,12 +120,12 @@ impl OverlayData { } } - pub(super) fn upload_width(&self, overlay: &mut OverlayManager) { + fn upload_width(&self, overlay: &mut OverlayManager) { let Some(handle) = self.data.handle else { log::debug!("{}: No overlay handle", self.state.name); return; }; - if let Err(e) = overlay.set_width(handle, self.state.width) { + if let Err(e) = overlay.set_width(handle, WIDTH) { panic!("Failed to set overlay width: {}", e); } } diff --git a/src/backend/openxr/mod.rs b/src/backend/openxr/mod.rs index 20f0509..de7ec28 100644 --- a/src/backend/openxr/mod.rs +++ b/src/backend/openxr/mod.rs @@ -186,13 +186,17 @@ pub fn openxr_run(running: Arc) -> Result<(), BackendError> { app_state.input_state.hmd = hmd_pose_from_views(&views); + overlays + .iter_mut() + .for_each(|o| o.state.auto_movement(&mut app_state)); + let pointer_lengths = interact(&mut overlays, &mut app_state); for (idx, len) in pointer_lengths.iter().enumerate() { lines.draw_from( pointer_lines[idx], app_state.input_state.pointers[idx].pose, *len, - 0, + app_state.input_state.pointers[idx].interaction.mode as usize + 1, ); } @@ -210,6 +214,7 @@ pub fn openxr_run(running: Arc) -> Result<(), BackendError> { o.init(&mut app_state); o.data.init = true; } + o.render(&mut app_state); if let Some(quad) = o.present_xr(&xr_state, &mut command_buffer) { diff --git a/src/backend/openxr/overlay.rs b/src/backend/openxr/overlay.rs index 3e7c961..20d962d 100644 --- a/src/backend/openxr/overlay.rs +++ b/src/backend/openxr/overlay.rs @@ -6,6 +6,7 @@ use super::{swapchain::SwapchainRenderData, transform_to_posef, XrState}; use crate::{ backend::{openxr::swapchain::create_swapchain_render_data, overlay::OverlayData}, graphics::WlxCommandBuffer, + state::AppState, }; use vulkano::image::view::ImageView; @@ -51,6 +52,11 @@ impl OverlayData { let sub_image = data.acquire_present_release(command_buffer, my_view); let posef = transform_to_posef(&self.state.transform); + let scale_x = self.state.transform.matrix3.col(0).length(); + log::info!("{}: scale_x = {}", self.state.name, scale_x); + let aspect_ratio = self.backend.extent()[1] as f32 / self.backend.extent()[0] as f32; + let scale_y = scale_x * aspect_ratio; + let quad = xr::CompositionLayerQuad::new() .pose(posef) .sub_image(sub_image) @@ -58,9 +64,8 @@ impl OverlayData { .layer_flags(CompositionLayerFlags::CORRECT_CHROMATIC_ABERRATION) .space(&xr.stage) .size(xr::Extent2Df { - width: self.state.width, - height: (self.backend.extent()[1] as f32 / self.backend.extent()[0] as f32) - * self.state.width, + width: scale_x, + height: scale_y, }); Some(quad) } diff --git a/src/backend/overlay.rs b/src/backend/overlay.rs index 042475a..be565e0 100644 --- a/src/backend/overlay.rs +++ b/src/backend/overlay.rs @@ -20,13 +20,13 @@ pub trait OverlayBackend: OverlayRenderer + InteractionHandler {} pub struct OverlayState { pub id: usize, pub name: Arc, - pub width: f32, pub size: (i32, i32), pub want_visible: bool, pub show_hide: bool, pub grabbable: bool, pub dirty: bool, pub transform: Affine3A, + pub spawn_scale: f32, // aka width pub spawn_point: Vec3A, pub spawn_rotation: Quat, pub relative_to: RelativeTo, @@ -39,13 +39,13 @@ impl Default for OverlayState { OverlayState { id: AUTO_INCREMENT.fetch_add(1, Ordering::Relaxed), name: Arc::from(""), - width: 1., size: (0, 0), want_visible: false, show_hide: false, grabbable: false, dirty: false, relative_to: RelativeTo::None, + spawn_scale: 1.0, spawn_point: Vec3A::NEG_Z, spawn_rotation: Quat::IDENTITY, transform: Affine3A::IDENTITY, @@ -80,8 +80,34 @@ where } impl OverlayState { - pub fn reset(&mut self, _app: &mut AppState) { - todo!() + pub fn parent_transform(&self, app: &AppState) -> Option { + match self.relative_to { + RelativeTo::None => None, + RelativeTo::Head => Some(app.input_state.hmd), + RelativeTo::Hand(idx) => Some(app.input_state.pointers[idx].pose), + } + } + pub fn auto_movement(&mut self, app: &mut AppState) { + if let Some(parent) = self.parent_transform(app) { + self.transform = parent + * Affine3A::from_scale_rotation_translation( + Vec3::ONE * self.spawn_scale, + self.spawn_rotation, + self.spawn_point.into(), + ); + } + } + pub fn reset(&mut self, app: &mut AppState) { + if let RelativeTo::None = self.relative_to { + let translation = app.input_state.hmd.transform_point3a(self.spawn_point); + self.transform = Affine3A::from_scale_rotation_translation( + Vec3::ONE * self.spawn_scale, + Quat::IDENTITY, + translation.into(), + ); + + self.realign(&app.input_state.hmd); + } } pub fn realign(&mut self, hmd: &Affine3A) { let to_hmd = hmd.translation - self.transform.translation; @@ -129,11 +155,7 @@ where T: Default, { pub fn init(&mut self, app: &mut AppState) { - self.state.transform.translation = app - .input_state - .hmd - .transform_point3a(self.state.spawn_point); - self.state.realign(&app.input_state.hmd); + self.state.reset(app); self.backend.init(app); } pub fn render(&mut self, app: &mut AppState) { diff --git a/src/overlays/keyboard.rs b/src/overlays/keyboard.rs index ea59f92..ecd7922 100644 --- a/src/overlays/keyboard.rs +++ b/src/overlays/keyboard.rs @@ -118,9 +118,9 @@ where state: OverlayState { name: Arc::from("kbd"), show_hide: true, - width, size: (size.x as _, size.y as _), grabbable: true, + spawn_scale: width, spawn_point: vec3a(0., -0.5, -1.), interaction_transform, ..Default::default() diff --git a/src/overlays/screen.rs b/src/overlays/screen.rs index 1190f0b..a1363d9 100644 --- a/src/overlays/screen.rs +++ b/src/overlays/screen.rs @@ -128,7 +128,7 @@ impl ScreenPipeline { graphics.create_pipeline( view, shaders.get("vert_common").unwrap().clone(), - shaders.get("frag_screen").unwrap().clone(), + shaders.get("frag_sprite").unwrap().clone(), Format::R8G8B8A8_UNORM, // ImageLayout::TransferSrcOptimal, // ImageLayout::TransferSrcOptimal, @@ -416,9 +416,9 @@ where want_visible: session.show_screens.iter().any(|s| s == &*output.name), show_hide: true, grabbable: true, - spawn_rotation: Quat::from_axis_angle(axis, angle), + spawn_scale: 1.5, spawn_point: vec3a(0., 0.5, -1.), - width: 1., + spawn_rotation: Quat::from_axis_angle(axis, angle), interaction_transform, ..Default::default() }, diff --git a/src/overlays/watch.rs b/src/overlays/watch.rs index 8663b35..a2af1bc 100644 --- a/src/overlays/watch.rs +++ b/src/overlays/watch.rs @@ -165,8 +165,8 @@ where state: OverlayState { name: "Watch".into(), size: (400, 200), - width: 0.065, want_visible: true, + spawn_scale: 0.065, spawn_point: state.session.watch_pos.into(), spawn_rotation: state.session.watch_rot, relative_to,