mirror of
https://github.com/wayvr-org/wayvr.git
synced 2026-10-28 16:02:47 +01:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0c6e319fbe | ||
|
|
4679961cb2 | ||
|
|
cb12357d68 | ||
|
|
b401fb28fd | ||
|
|
06478bbfc9 | ||
|
|
b57b77b06a | ||
|
|
5a077e394c | ||
|
|
a08c260898 | ||
|
|
45d08cd89b | ||
|
|
49b9cc361d | ||
|
|
2f8dcaf110 | ||
|
|
473c6e2038 | ||
|
|
4c91470b5c | ||
|
|
85e8e80538 | ||
|
|
49e1e8639d | ||
|
|
88bcd42e56 | ||
|
|
38395c9183 | ||
|
|
19bc4a5df2 | ||
|
|
ed096fffce | ||
|
|
cd297376a8 | ||
|
|
e7456a9b0a | ||
|
|
507c0677c8 | ||
|
|
1d9b60fc07 | ||
|
|
85d9ea9127 | ||
|
|
a55ade6741 | ||
|
|
5800d7d99d | ||
|
|
27d77ad638 | ||
|
|
2aed560950 | ||
|
|
1a70ea4fcc | ||
|
|
c73a01fb7f | ||
|
|
97fd6c1fc0 | ||
|
|
39ce2a7c00 | ||
|
|
0030ad43eb | ||
|
|
3006e52795 | ||
|
|
cfb432622e | ||
|
|
b49add2e89 | ||
|
|
da1936823f | ||
|
|
f42572d4cb | ||
|
|
d562d4b236 | ||
|
|
75dcfc8096 |
No files matched your search
Generated
+5
-5
@@ -1081,7 +1081,7 @@ version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
|
||||
dependencies = [
|
||||
"libloading 0.8.1",
|
||||
"libloading 0.7.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2198,7 +2198,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ovr_overlay"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/galister/ovr_overlay_oyasumi#c9794ab4439242fbaa908a2c625ed47fcf173508"
|
||||
source = "git+https://github.com/galister/ovr_overlay_oyasumi#61e0e77770212d64a76775a8c76637d1ca935942"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"derive_more",
|
||||
@@ -2213,7 +2213,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ovr_overlay_sys"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/galister/ovr_overlay_oyasumi#c9794ab4439242fbaa908a2c625ed47fcf173508"
|
||||
source = "git+https://github.com/galister/ovr_overlay_oyasumi#61e0e77770212d64a76775a8c76637d1ca935942"
|
||||
dependencies = [
|
||||
"autocxx",
|
||||
"autocxx-build",
|
||||
@@ -3703,7 +3703,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "wlx-capture"
|
||||
version = "0.2.1"
|
||||
source = "git+https://github.com/galister/wlx-capture#9ba8a769378f2cd049baef947a0de8195eeae2a5"
|
||||
source = "git+https://github.com/galister/wlx-capture#9c5368ef4535b7525de41d3ba5b076fb326e974c"
|
||||
dependencies = [
|
||||
"ashpd",
|
||||
"drm-fourcc",
|
||||
@@ -3722,7 +3722,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wlx-overlay-s"
|
||||
version = "0.2.3"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"ash",
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@ debug = true
|
||||
|
||||
[package]
|
||||
name = "wlx-overlay-s"
|
||||
version = "0.2.3"
|
||||
version = "0.3.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
@@ -43,7 +43,7 @@ strum = { version = "0.25.0", features = ["derive"] }
|
||||
thiserror = "1.0.56"
|
||||
vulkano = { git = "https://github.com/vulkano-rs/vulkano", rev = "94f50f1" }
|
||||
vulkano-shaders = { git = "https://github.com/vulkano-rs/vulkano", rev = "94f50f1" }
|
||||
wlx-capture = { git = "https://github.com/galister/wlx-capture" }
|
||||
wlx-capture = { git = "https://github.com/galister/wlx-capture", default-features = false }
|
||||
xdg = "2.5.2"
|
||||
|
||||
[features]
|
||||
|
||||
@@ -18,15 +18,18 @@ We are available on either:
|
||||
|
||||
Questions/issues specific to WlxOverlay-S will be handled in the `wlxoverlay` chat room.
|
||||
|
||||
# First Setup
|
||||
# Setup
|
||||
|
||||
Recommend grabbing [rustup](https://rustup.rs/) if you don't have it yet.
|
||||
1. Grab the latest AppImage from [Releases](https://github.com/galister/wlx-overlay-s/releases).
|
||||
1. `chmod +x WlxOverlay-S-*.AppImage`
|
||||
1. Start Monado or SteamVR.
|
||||
1. Run the overlay
|
||||
|
||||
Start Monado or SteamVR.
|
||||
AUR package is [wlx-overlay-s-git](https://aur.archlinux.org/packages/wlx-overlay-s-git).
|
||||
|
||||
```sh
|
||||
cargo run --release
|
||||
```
|
||||
You may also want to [build from source](https://github.com/galister/wlx-overlay-s/wiki/Building-from-Source).
|
||||
|
||||
# First Start
|
||||
|
||||
**If you get a screen share pop-up, check the terminal and select the screens in the order it tells you to.**
|
||||
|
||||
|
||||
@@ -71,6 +71,9 @@ impl InputState {
|
||||
if hand.now.space_drag != hand.before.space_drag {
|
||||
log::debug!("Hand {}: space_drag {}", hand.idx, hand.now.space_drag);
|
||||
}
|
||||
if hand.now.space_rotate != hand.before.space_rotate {
|
||||
log::debug!("Hand {}: space_rotate {}", hand.idx, hand.now.space_rotate);
|
||||
}
|
||||
if hand.now.click_modifier_right != hand.before.click_modifier_right {
|
||||
log::debug!(
|
||||
"Hand {}: click_modifier_right {}",
|
||||
@@ -159,6 +162,7 @@ impl Default for InteractionState {
|
||||
pub struct Pointer {
|
||||
pub idx: usize,
|
||||
pub pose: Affine3A,
|
||||
pub raw_pose: Affine3A,
|
||||
pub now: PointerState,
|
||||
pub before: PointerState,
|
||||
pub last_click: Instant,
|
||||
@@ -171,6 +175,7 @@ impl Pointer {
|
||||
Self {
|
||||
idx,
|
||||
pose: Affine3A::IDENTITY,
|
||||
raw_pose: Affine3A::IDENTITY,
|
||||
now: Default::default(),
|
||||
before: Default::default(),
|
||||
last_click: Instant::now(),
|
||||
@@ -187,6 +192,7 @@ pub struct PointerState {
|
||||
pub alt_click: bool,
|
||||
pub show_hide: bool,
|
||||
pub space_drag: bool,
|
||||
pub space_rotate: bool,
|
||||
pub click_modifier_right: bool,
|
||||
pub click_modifier_middle: bool,
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ impl NotificationManager {
|
||||
|
||||
let sender2 = self.tx_toast.clone();
|
||||
let result = c.add_match(rule_with_eavesdrop, move |_: (), _, msg| {
|
||||
if let Ok(toast) = parse_dbus(&msg) {
|
||||
if let Ok(toast) = parse_dbus(msg) {
|
||||
match sender2.try_send(toast) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
|
||||
@@ -7,12 +7,12 @@ use thiserror::Error;
|
||||
use crate::backend::common::{BackendError, ColorChannel};
|
||||
|
||||
pub trait Affine3AConvert {
|
||||
fn from_affine(affine: Affine3A) -> Self;
|
||||
fn from_affine(affine: &Affine3A) -> Self;
|
||||
fn to_affine(&self) -> Affine3A;
|
||||
}
|
||||
|
||||
impl Affine3AConvert for Matrix3x4 {
|
||||
fn from_affine(affine: Affine3A) -> Self {
|
||||
fn from_affine(affine: &Affine3A) -> Self {
|
||||
Matrix3x4([
|
||||
[
|
||||
affine.matrix3.x_axis.x,
|
||||
@@ -46,7 +46,7 @@ impl Affine3AConvert for Matrix3x4 {
|
||||
}
|
||||
|
||||
impl Affine3AConvert for HmdMatrix34_t {
|
||||
fn from_affine(affine: Affine3A) -> Self {
|
||||
fn from_affine(affine: &Affine3A) -> Self {
|
||||
HmdMatrix34_t {
|
||||
m: [
|
||||
[
|
||||
@@ -101,7 +101,7 @@ impl From<OVRError> for BackendError {
|
||||
|
||||
use cstr::cstr;
|
||||
const STEAMVR_SECTION: &CStr = cstr!("steamvr");
|
||||
const COLOR_GAIN_CSTR: [&'static CStr; 3] = [
|
||||
const COLOR_GAIN_CSTR: [&CStr; 3] = [
|
||||
cstr!("hmdDisplayColorGainR"),
|
||||
cstr!("hmdDisplayColorGainG"),
|
||||
cstr!("hmdDisplayColorGainB"),
|
||||
|
||||
@@ -36,6 +36,7 @@ const PATH_SCROLL: &str = "/actions/default/in/Scroll";
|
||||
const PATH_ALT_CLICK: &str = "/actions/default/in/AltClick";
|
||||
const PATH_SHOW_HIDE: &str = "/actions/default/in/ShowHide";
|
||||
const PATH_SPACE_DRAG: &str = "/actions/default/in/SpaceDrag";
|
||||
const PATH_SPACE_ROTATE: &str = "/actions/default/in/SpaceRotate";
|
||||
const PATH_CLICK_MODIFIER_RIGHT: &str = "/actions/default/in/ClickModifierRight";
|
||||
const PATH_CLICK_MODIFIER_MIDDLE: &str = "/actions/default/in/ClickModifierMiddle";
|
||||
|
||||
@@ -50,12 +51,14 @@ pub(super) struct OpenVrInputSource {
|
||||
alt_click_hnd: ActionHandle,
|
||||
show_hide_hnd: ActionHandle,
|
||||
space_drag_hnd: ActionHandle,
|
||||
space_rotate_hnd: ActionHandle,
|
||||
click_modifier_right_hnd: ActionHandle,
|
||||
click_modifier_middle_hnd: ActionHandle,
|
||||
}
|
||||
|
||||
pub(super) struct OpenVrHandSource {
|
||||
has_pose: bool,
|
||||
device: Option<TrackedDeviceIndex>,
|
||||
input_hnd: InputValueHandle,
|
||||
pose_hnd: ActionHandle,
|
||||
haptics_hnd: ActionHandle,
|
||||
@@ -71,6 +74,7 @@ impl OpenVrInputSource {
|
||||
let alt_click_hnd = input.get_action_handle(PATH_ALT_CLICK)?;
|
||||
let show_hide_hnd = input.get_action_handle(PATH_SHOW_HIDE)?;
|
||||
let space_drag_hnd = input.get_action_handle(PATH_SPACE_DRAG)?;
|
||||
let space_rotate_hnd = input.get_action_handle(PATH_SPACE_ROTATE)?;
|
||||
let click_modifier_right_hnd = input.get_action_handle(PATH_CLICK_MODIFIER_RIGHT)?;
|
||||
let click_modifier_middle_hnd = input.get_action_handle(PATH_CLICK_MODIFIER_MIDDLE)?;
|
||||
|
||||
@@ -91,6 +95,7 @@ impl OpenVrInputSource {
|
||||
|
||||
let hands: [OpenVrHandSource; 2] = array::from_fn(|i| OpenVrHandSource {
|
||||
has_pose: false,
|
||||
device: None,
|
||||
input_hnd: input_hnd[i],
|
||||
pose_hnd: pose_hnd[i],
|
||||
haptics_hnd: haptics_hnd[i],
|
||||
@@ -104,6 +109,7 @@ impl OpenVrInputSource {
|
||||
alt_click_hnd,
|
||||
show_hide_hnd,
|
||||
space_drag_hnd,
|
||||
space_rotate_hnd,
|
||||
click_modifier_right_hnd,
|
||||
click_modifier_middle_hnd,
|
||||
hands,
|
||||
@@ -124,6 +130,7 @@ impl OpenVrInputSource {
|
||||
|
||||
pub fn update(
|
||||
&mut self,
|
||||
universe: ETrackingUniverseOrigin,
|
||||
input: &mut InputManager,
|
||||
system: &mut SystemManager,
|
||||
app: &mut AppState,
|
||||
@@ -138,12 +145,19 @@ impl OpenVrInputSource {
|
||||
|
||||
let _ = input.update_actions(&mut [aas]);
|
||||
|
||||
let universe = ETrackingUniverseOrigin::TrackingUniverseStanding;
|
||||
let devices = system.get_device_to_absolute_tracking_pose(universe.clone(), 0.005);
|
||||
app.input_state.hmd = devices[0].mDeviceToAbsoluteTracking.to_affine();
|
||||
|
||||
for i in 0..2 {
|
||||
let hand = &mut self.hands[i];
|
||||
let app_hand = &mut app.input_state.pointers[i];
|
||||
|
||||
if let Some(device) = hand.device {
|
||||
app_hand.raw_pose = devices[device.0 as usize]
|
||||
.mDeviceToAbsoluteTracking
|
||||
.to_affine();
|
||||
}
|
||||
|
||||
hand.has_pose = false;
|
||||
|
||||
let _ = input
|
||||
@@ -183,6 +197,11 @@ impl OpenVrInputSource {
|
||||
.map(|x| x.0.bState)
|
||||
.unwrap_or(false);
|
||||
|
||||
app_hand.now.space_rotate = input
|
||||
.get_digital_action_data(self.space_rotate_hnd, hand.input_hnd)
|
||||
.map(|x| x.0.bState)
|
||||
.unwrap_or(false);
|
||||
|
||||
app_hand.now.click_modifier_right = input
|
||||
.get_digital_action_data(self.click_modifier_right_hnd, hand.input_hnd)
|
||||
.map(|x| x.0.bState)
|
||||
@@ -198,14 +217,10 @@ impl OpenVrInputSource {
|
||||
.map(|x| x.0.y)
|
||||
.unwrap_or(0.0);
|
||||
}
|
||||
|
||||
let devices = system.get_device_to_absolute_tracking_pose(universe, 0.005);
|
||||
app.input_state.hmd = devices[0].mDeviceToAbsoluteTracking.to_affine();
|
||||
}
|
||||
|
||||
pub fn update_devices(&mut self, system: &mut SystemManager, app: &mut AppState) {
|
||||
app.input_state.devices.clear();
|
||||
|
||||
for idx in 0..TrackedDeviceIndex::MAX {
|
||||
let device = TrackedDeviceIndex::new(idx as _).unwrap(); // safe
|
||||
if !system.is_tracked_device_connected(device) {
|
||||
@@ -220,9 +235,11 @@ impl OpenVrInputSource {
|
||||
let role = system.get_controller_role_for_tracked_device_index(device);
|
||||
match role {
|
||||
ETrackedControllerRole::TrackedControllerRole_LeftHand => {
|
||||
self.hands[0].device = Some(device);
|
||||
TrackedDeviceRole::LeftHand
|
||||
}
|
||||
ETrackedControllerRole::TrackedControllerRole_RightHand => {
|
||||
self.hands[1].device = Some(device);
|
||||
TrackedDeviceRole::RightHand
|
||||
}
|
||||
_ => continue,
|
||||
@@ -294,9 +311,7 @@ fn get_tracked_device(
|
||||
pub fn set_action_manifest(input: &mut InputManager) -> anyhow::Result<()> {
|
||||
let action_path = CONFIG_ROOT_PATH.join("actions.json");
|
||||
|
||||
if !action_path.is_file() {
|
||||
File::create(&action_path)?.write_all(include_bytes!("../../res/actions.json"))?;
|
||||
}
|
||||
File::create(&action_path)?.write_all(include_bytes!("../../res/actions.json"))?;
|
||||
|
||||
let binding_path = CONFIG_ROOT_PATH.join("actions_binding_knuckles.json");
|
||||
if !binding_path.is_file() {
|
||||
|
||||
@@ -5,6 +5,7 @@ use std::sync::Arc;
|
||||
use glam::{Affine3A, Vec3, Vec3A, Vec4};
|
||||
use idmap::IdMap;
|
||||
use ovr_overlay::overlay::OverlayManager;
|
||||
use ovr_overlay::sys::ETrackingUniverseOrigin;
|
||||
use vulkano::command_buffer::CommandBufferUsage;
|
||||
use vulkano::format::Format;
|
||||
use vulkano::image::view::ImageView;
|
||||
@@ -141,6 +142,7 @@ impl LinePool {
|
||||
|
||||
pub fn update(
|
||||
&mut self,
|
||||
universe: ETrackingUniverseOrigin,
|
||||
overlay: &mut OverlayManager,
|
||||
app: &mut AppState,
|
||||
) -> anyhow::Result<()> {
|
||||
@@ -152,7 +154,7 @@ impl LinePool {
|
||||
data.state.dirty = false;
|
||||
}
|
||||
|
||||
data.upload_transform(overlay);
|
||||
data.upload_transform(universe.clone(), overlay);
|
||||
data.upload_color(overlay);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,12 +9,18 @@ use crate::config_io::CONFIG_ROOT_PATH;
|
||||
const APP_KEY: &str = "galister.wlxoverlay-s";
|
||||
|
||||
pub(super) fn install_manifest(app_mgr: &mut ApplicationsManager) -> anyhow::Result<()> {
|
||||
let executable_pathbuf = std::env::current_exe()?;
|
||||
let executable_path = executable_pathbuf
|
||||
.to_str()
|
||||
.ok_or_else(|| anyhow::anyhow!("Invalid executable path"))?;
|
||||
let manifest_path = CONFIG_ROOT_PATH.join("wlx-overlay-s.vrmanifest");
|
||||
|
||||
let appimage_path = std::env::var("APPIMAGE");
|
||||
let executable_pathbuf = std::env::current_exe()?;
|
||||
|
||||
let executable_path = match appimage_path {
|
||||
Ok(ref path) => path,
|
||||
Err(_) => executable_pathbuf
|
||||
.to_str()
|
||||
.ok_or_else(|| anyhow::anyhow!("Invalid executable path"))?,
|
||||
};
|
||||
|
||||
if let Ok(true) = app_mgr.is_application_installed(APP_KEY) {
|
||||
if let Ok(mut file) = File::open(&manifest_path) {
|
||||
let mut buf = String::new();
|
||||
|
||||
+52
-35
@@ -1,7 +1,7 @@
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
atomic::{AtomicBool, AtomicUsize, Ordering},
|
||||
Arc,
|
||||
},
|
||||
time::{Duration, Instant},
|
||||
@@ -46,6 +46,8 @@ pub mod manifest;
|
||||
pub mod overlay;
|
||||
pub mod playspace;
|
||||
|
||||
static FRAME_COUNTER: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
pub fn openvr_uninstall() {
|
||||
let app_type = EVRApplicationType::VRApplication_Overlay;
|
||||
let Ok(context) = ovr_overlay::Context::init(app_type) else {
|
||||
@@ -67,15 +69,15 @@ pub fn openvr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
|
||||
log::info!("Using OpenVR runtime");
|
||||
|
||||
let mut app_mgr = context.applications_mngr();
|
||||
let mut input_mngr = context.input_mngr();
|
||||
let mut system_mngr = context.system_mngr();
|
||||
let mut overlay_mngr = context.overlay_mngr();
|
||||
let mut settings_mngr = context.settings_mngr();
|
||||
let mut input_mgr = context.input_mngr();
|
||||
let mut system_mgr = context.system_mngr();
|
||||
let mut overlay_mgr = context.overlay_mngr();
|
||||
let mut settings_mgr = context.settings_mngr();
|
||||
let mut chaperone_mgr = context.chaperone_setup_mngr();
|
||||
let mut compositor_mngr = context.compositor_mngr();
|
||||
let mut compositor_mgr = context.compositor_mngr();
|
||||
|
||||
let device_extensions_fn = |device: &PhysicalDevice| {
|
||||
let names = compositor_mngr.get_vulkan_device_extensions_required(device.handle().as_raw());
|
||||
let names = compositor_mgr.get_vulkan_device_extensions_required(device.handle().as_raw());
|
||||
let ext = DeviceExtensions::from_iter(names.iter().map(|s| s.as_str()));
|
||||
ext
|
||||
};
|
||||
@@ -98,18 +100,20 @@ pub fn openvr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
|
||||
notifications.run_dbus();
|
||||
notifications.run_udp();
|
||||
|
||||
let mut space_mover = playspace::PlayspaceMover::new();
|
||||
let mut playspace = playspace::PlayspaceMover::new();
|
||||
playspace.playspace_changed(&mut compositor_mgr, &mut chaperone_mgr);
|
||||
|
||||
#[cfg(feature = "osc")]
|
||||
let mut osc_sender =
|
||||
crate::backend::osc::OscSender::new(state.session.config.osc_out_port).ok();
|
||||
|
||||
state.hid_provider.set_desktop_extent(overlays.extent);
|
||||
|
||||
set_action_manifest(&mut input_mngr)?;
|
||||
set_action_manifest(&mut input_mgr)?;
|
||||
|
||||
let mut input_source = OpenVrInputSource::new(&mut input_mngr)?;
|
||||
let mut input_source = OpenVrInputSource::new(&mut input_mgr)?;
|
||||
|
||||
let Ok(refresh_rate) = system_mngr.get_tracked_device_property::<f32>(
|
||||
let Ok(refresh_rate) = system_mgr.get_tracked_device_property::<f32>(
|
||||
TrackedDeviceIndex::HMD,
|
||||
ETrackedDeviceProperty::Prop_DisplayFrequency_Float,
|
||||
) else {
|
||||
@@ -122,7 +126,9 @@ pub fn openvr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
|
||||
|
||||
let watch_id = overlays.get_by_name(WATCH_NAME).unwrap().state.id; // want panic
|
||||
|
||||
let frame_time = (1000.0 / refresh_rate).floor() * 0.001;
|
||||
// want at least half refresh rate
|
||||
let frame_timeout = 2 * (1000.0 / refresh_rate).floor() as u32;
|
||||
|
||||
let mut next_device_update = Instant::now();
|
||||
let mut due_tasks = VecDeque::with_capacity(4);
|
||||
|
||||
@@ -130,12 +136,16 @@ pub fn openvr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
|
||||
let pointer_lines = [lines.allocate(), lines.allocate()];
|
||||
|
||||
'main_loop: loop {
|
||||
let _ = overlay_mgr.wait_frame_sync(frame_timeout);
|
||||
|
||||
if !running.load(Ordering::Relaxed) {
|
||||
log::warn!("Received shutdown signal.");
|
||||
break 'main_loop;
|
||||
}
|
||||
|
||||
while let Some(event) = system_mngr.poll_next_event() {
|
||||
let cur_frame = FRAME_COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
while let Some(event) = system_mgr.poll_next_event() {
|
||||
match event.event_type {
|
||||
EVREventType::VREvent_Quit => {
|
||||
log::warn!("Received quit event, shutting down.");
|
||||
@@ -146,12 +156,18 @@ pub fn openvr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
|
||||
| EVREventType::VREvent_TrackedDeviceUpdated => {
|
||||
next_device_update = Instant::now();
|
||||
}
|
||||
EVREventType::VREvent_SeatedZeroPoseReset
|
||||
| EVREventType::VREvent_StandingZeroPoseReset
|
||||
| EVREventType::VREvent_ChaperoneUniverseHasChanged
|
||||
| EVREventType::VREvent_SceneApplicationChanged => {
|
||||
playspace.playspace_changed(&mut compositor_mgr, &mut chaperone_mgr);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if next_device_update <= Instant::now() {
|
||||
input_source.update_devices(&mut system_mngr, &mut state);
|
||||
input_source.update_devices(&mut system_mgr, &mut state);
|
||||
next_device_update = Instant::now() + Duration::from_secs(30);
|
||||
}
|
||||
|
||||
@@ -171,9 +187,10 @@ pub fn openvr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
|
||||
continue;
|
||||
};
|
||||
|
||||
let Some((state, backend)) = f(&mut state) else {
|
||||
let Some((mut state, backend)) = f(&mut state) else {
|
||||
continue;
|
||||
};
|
||||
state.birthframe = cur_frame;
|
||||
|
||||
overlays.add(OverlayData {
|
||||
state,
|
||||
@@ -183,26 +200,35 @@ pub fn openvr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
|
||||
}
|
||||
TaskType::DropOverlay(sel) => {
|
||||
if let Some(o) = overlays.mut_by_selector(&sel) {
|
||||
o.destroy(&mut overlay_mngr);
|
||||
overlays.remove_by_selector(&sel);
|
||||
if o.state.birthframe < cur_frame {
|
||||
o.destroy(&mut overlay_mgr);
|
||||
overlays.remove_by_selector(&sel);
|
||||
}
|
||||
}
|
||||
}
|
||||
TaskType::System(task) => match task {
|
||||
SystemTask::ColorGain(channel, value) => {
|
||||
let _ = adjust_gain(&mut settings_mngr, channel, value);
|
||||
let _ = adjust_gain(&mut settings_mgr, channel, value);
|
||||
}
|
||||
SystemTask::FixFloor => {
|
||||
space_mover.fix_floor(&mut chaperone_mgr, &state.input_state);
|
||||
playspace.fix_floor(&mut chaperone_mgr, &state.input_state);
|
||||
}
|
||||
SystemTask::ResetPlayspace => {
|
||||
space_mover.reset_offset(&mut chaperone_mgr);
|
||||
playspace.reset_offset(&mut chaperone_mgr, &state.input_state);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
let universe = playspace.get_universe();
|
||||
|
||||
state.input_state.pre_update();
|
||||
input_source.update(&mut input_mngr, &mut system_mngr, &mut state);
|
||||
input_source.update(
|
||||
universe.clone(),
|
||||
&mut input_mgr,
|
||||
&mut system_mgr,
|
||||
&mut state,
|
||||
);
|
||||
state.input_state.post_update();
|
||||
|
||||
if state
|
||||
@@ -219,7 +245,7 @@ pub fn openvr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
|
||||
.for_each(|o| o.state.auto_movement(&mut state));
|
||||
|
||||
watch_fade(&mut state, overlays.mut_by_id(watch_id).unwrap()); // want panic
|
||||
space_mover.update(&mut chaperone_mgr, &mut overlays, &state);
|
||||
playspace.update(&mut chaperone_mgr, &mut overlays, &state);
|
||||
|
||||
let lengths_haptics = interact(&mut overlays, &mut state);
|
||||
for (idx, (len, haptics)) in lengths_haptics.iter().enumerate() {
|
||||
@@ -231,14 +257,14 @@ pub fn openvr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
|
||||
&state.input_state.hmd,
|
||||
);
|
||||
if let Some(haptics) = haptics {
|
||||
input_source.haptics(&mut input_mngr, idx, haptics)
|
||||
input_source.haptics(&mut input_mgr, idx, haptics)
|
||||
}
|
||||
}
|
||||
|
||||
lines.update(&mut overlay_mngr, &mut state)?;
|
||||
lines.update(universe.clone(), &mut overlay_mgr, &mut state)?;
|
||||
|
||||
for o in overlays.iter_mut() {
|
||||
o.after_input(&mut overlay_mngr, &mut state)?;
|
||||
o.after_input(&mut overlay_mgr, &mut state)?;
|
||||
}
|
||||
|
||||
#[cfg(feature = "osc")]
|
||||
@@ -258,22 +284,13 @@ pub fn openvr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
|
||||
|
||||
overlays
|
||||
.iter_mut()
|
||||
.for_each(|o| o.after_render(&mut overlay_mngr, &state.graphics));
|
||||
.for_each(|o| o.after_render(universe.clone(), &mut overlay_mgr, &state.graphics));
|
||||
|
||||
// chaperone
|
||||
|
||||
// close font handles?
|
||||
|
||||
state.hid_provider.on_new_frame();
|
||||
|
||||
let mut seconds_since_vsync = 0f32;
|
||||
std::thread::sleep(Duration::from_secs_f32(
|
||||
if system_mngr.get_time_since_last_vsync(&mut seconds_since_vsync, &mut 0u64) {
|
||||
(frame_time - seconds_since_vsync).max(0.0)
|
||||
} else {
|
||||
frame_time
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
log::warn!("OpenVR shutdown");
|
||||
|
||||
@@ -79,10 +79,15 @@ impl OverlayData<OpenVrOverlayData> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn after_render(&mut self, overlay: &mut OverlayManager, graphics: &WlxGraphics) {
|
||||
pub(super) fn after_render(
|
||||
&mut self,
|
||||
universe: ETrackingUniverseOrigin,
|
||||
overlay: &mut OverlayManager,
|
||||
graphics: &WlxGraphics,
|
||||
) {
|
||||
if self.data.visible {
|
||||
if self.state.dirty {
|
||||
self.upload_transform(overlay);
|
||||
self.upload_transform(universe, overlay);
|
||||
self.upload_alpha(overlay);
|
||||
self.state.dirty = false;
|
||||
}
|
||||
@@ -185,19 +190,19 @@ impl OverlayData<OpenVrOverlayData> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn upload_transform(&self, overlay: &mut OverlayManager) {
|
||||
pub(super) fn upload_transform(
|
||||
&self,
|
||||
universe: ETrackingUniverseOrigin,
|
||||
overlay: &mut OverlayManager,
|
||||
) {
|
||||
let Some(handle) = self.data.handle else {
|
||||
log::debug!("{}: No overlay handle", self.state.name);
|
||||
return;
|
||||
};
|
||||
|
||||
let transform = Matrix3x4::from_affine(self.state.transform);
|
||||
let transform = Matrix3x4::from_affine(&self.state.transform);
|
||||
|
||||
if let Err(e) = overlay.set_transform_absolute(
|
||||
handle,
|
||||
ETrackingUniverseOrigin::TrackingUniverseStanding,
|
||||
&transform,
|
||||
) {
|
||||
if let Err(e) = overlay.set_transform_absolute(handle, universe, &transform) {
|
||||
log::error!(
|
||||
"{}: Failed to set overlay transform: {}",
|
||||
self.state.name,
|
||||
|
||||
+239
-44
@@ -1,25 +1,35 @@
|
||||
use glam::Vec3A;
|
||||
use ovr_overlay::{chaperone_setup::ChaperoneSetupManager, sys::EChaperoneConfigFile};
|
||||
use glam::{Affine3A, Quat, Vec3, Vec3A};
|
||||
use ovr_overlay::{
|
||||
chaperone_setup::ChaperoneSetupManager,
|
||||
compositor::CompositorManager,
|
||||
sys::{EChaperoneConfigFile, ETrackingUniverseOrigin, HmdMatrix34_t},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
backend::{common::OverlayContainer, input::InputState},
|
||||
state::AppState,
|
||||
};
|
||||
|
||||
use super::overlay::OpenVrOverlayData;
|
||||
use super::{helpers::Affine3AConvert, overlay::OpenVrOverlayData};
|
||||
|
||||
struct MoverData<T> {
|
||||
pose: Affine3A,
|
||||
hand: usize,
|
||||
hand_pose: T,
|
||||
}
|
||||
|
||||
pub(super) struct PlayspaceMover {
|
||||
drag_hand: Option<usize>,
|
||||
offset: Vec3A,
|
||||
start_position: Vec3A,
|
||||
universe: ETrackingUniverseOrigin,
|
||||
drag: Option<MoverData<Vec3A>>,
|
||||
rotate: Option<MoverData<Quat>>,
|
||||
}
|
||||
|
||||
impl PlayspaceMover {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
drag_hand: None,
|
||||
offset: Vec3A::ZERO,
|
||||
start_position: Vec3A::ZERO,
|
||||
universe: ETrackingUniverseOrigin::TrackingUniverseRawAndUncalibrated,
|
||||
drag: None,
|
||||
rotate: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,68 +39,253 @@ impl PlayspaceMover {
|
||||
overlays: &mut OverlayContainer<OpenVrOverlayData>,
|
||||
state: &AppState,
|
||||
) {
|
||||
if let Some(hand) = self.drag_hand {
|
||||
let pointer = &state.input_state.pointers[hand];
|
||||
if !pointer.now.space_drag {
|
||||
self.drag_hand = None;
|
||||
log::info!("End space drag");
|
||||
let universe = self.universe.clone();
|
||||
|
||||
if let Some(data) = self.rotate.as_mut() {
|
||||
let pointer = &state.input_state.pointers[data.hand];
|
||||
if !pointer.now.space_rotate {
|
||||
self.rotate = None;
|
||||
log::info!("End space rotate");
|
||||
return;
|
||||
}
|
||||
|
||||
let hand_pos = state.input_state.pointers[hand].pose.translation;
|
||||
let relative_pos = hand_pos - self.start_position;
|
||||
let new_hand =
|
||||
Quat::from_affine3(&(data.pose * state.input_state.pointers[data.hand].raw_pose));
|
||||
|
||||
let dq = new_hand * data.hand_pose.conjugate();
|
||||
let rel_y = f32::atan2(
|
||||
2.0 * (dq.y * dq.w + dq.x * dq.z),
|
||||
(2.0 * (dq.w * dq.w + dq.x * dq.x)) - 1.0,
|
||||
);
|
||||
|
||||
let mut space_transform = Affine3A::from_rotation_y(rel_y);
|
||||
let offset = (space_transform.transform_vector3a(state.input_state.hmd.translation)
|
||||
- state.input_state.hmd.translation)
|
||||
* -1.0;
|
||||
let mut overlay_transform = Affine3A::from_rotation_y(-rel_y);
|
||||
|
||||
overlay_transform.translation = offset;
|
||||
space_transform.translation = offset;
|
||||
|
||||
overlays.iter_mut().for_each(|overlay| {
|
||||
if overlay.state.grabbable {
|
||||
overlay.state.dirty = true;
|
||||
overlay.state.transform.translation += relative_pos * -1.0;
|
||||
overlay.state.transform.translation =
|
||||
overlay_transform.transform_point3a(overlay.state.transform.translation);
|
||||
}
|
||||
});
|
||||
|
||||
self.offset += relative_pos;
|
||||
self.apply_offset(chaperone_mgr);
|
||||
data.pose = data.pose * space_transform;
|
||||
data.hand_pose = new_hand;
|
||||
|
||||
if self.universe == ETrackingUniverseOrigin::TrackingUniverseStanding {
|
||||
apply_chaperone_transform(space_transform.inverse(), chaperone_mgr);
|
||||
}
|
||||
set_working_copy(&universe, chaperone_mgr, &data.pose);
|
||||
chaperone_mgr.commit_working_copy(EChaperoneConfigFile::EChaperoneConfigFile_Live);
|
||||
} else {
|
||||
for (i, pointer) in state.input_state.pointers.iter().enumerate() {
|
||||
if pointer.now.space_rotate {
|
||||
let Some(mat) = get_working_copy(&universe, chaperone_mgr) else {
|
||||
log::warn!("Can't space rotate - failed to get zero pose");
|
||||
return;
|
||||
};
|
||||
let hand_pose = Quat::from_affine3(&(mat * pointer.raw_pose));
|
||||
self.rotate = Some(MoverData {
|
||||
pose: mat,
|
||||
hand: i,
|
||||
hand_pose,
|
||||
});
|
||||
self.drag = None;
|
||||
log::info!("Start space rotate");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(data) = self.drag.as_mut() {
|
||||
let pointer = &state.input_state.pointers[data.hand];
|
||||
if !pointer.now.space_drag {
|
||||
self.drag = None;
|
||||
log::info!("End space drag");
|
||||
return;
|
||||
}
|
||||
|
||||
let new_hand = data
|
||||
.pose
|
||||
.transform_point3a(state.input_state.pointers[data.hand].raw_pose.translation);
|
||||
let relative_pos = new_hand - data.hand_pose;
|
||||
|
||||
if relative_pos.length_squared() > 1000.0 {
|
||||
log::warn!("Space drag too fast, ignoring");
|
||||
return;
|
||||
}
|
||||
|
||||
let overlay_offset = data.pose.inverse().transform_vector3a(relative_pos) * -1.0;
|
||||
|
||||
overlays.iter_mut().for_each(|overlay| {
|
||||
if overlay.state.grabbable {
|
||||
overlay.state.dirty = true;
|
||||
overlay.state.transform.translation += overlay_offset;
|
||||
}
|
||||
});
|
||||
|
||||
data.pose.translation += relative_pos;
|
||||
data.hand_pose = new_hand;
|
||||
|
||||
if self.universe == ETrackingUniverseOrigin::TrackingUniverseStanding {
|
||||
apply_chaperone_offset(overlay_offset, chaperone_mgr);
|
||||
}
|
||||
set_working_copy(&universe, chaperone_mgr, &data.pose);
|
||||
chaperone_mgr.commit_working_copy(EChaperoneConfigFile::EChaperoneConfigFile_Live);
|
||||
} else {
|
||||
for (i, pointer) in state.input_state.pointers.iter().enumerate() {
|
||||
if pointer.now.space_drag {
|
||||
self.drag_hand = Some(i);
|
||||
self.start_position = pointer.pose.translation;
|
||||
let Some(mat) = get_working_copy(&universe, chaperone_mgr) else {
|
||||
log::warn!("Can't space drag - failed to get zero pose");
|
||||
return;
|
||||
};
|
||||
let hand_pos = mat.transform_point3a(pointer.raw_pose.translation);
|
||||
self.drag = Some(MoverData {
|
||||
pose: mat,
|
||||
hand: i,
|
||||
hand_pose: hand_pos,
|
||||
});
|
||||
self.rotate = None;
|
||||
log::info!("Start space drag");
|
||||
break;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset_offset(&mut self, chaperone_mgr: &mut ChaperoneSetupManager) {
|
||||
self.offset = Vec3A::ZERO;
|
||||
self.apply_offset(chaperone_mgr);
|
||||
pub fn reset_offset(&mut self, chaperone_mgr: &mut ChaperoneSetupManager, input: &InputState) {
|
||||
let mut height = 1.6;
|
||||
if let Some(mat) = get_working_copy(&self.universe, chaperone_mgr) {
|
||||
height = input.hmd.translation.y - mat.translation.y;
|
||||
if self.universe == ETrackingUniverseOrigin::TrackingUniverseStanding {
|
||||
apply_chaperone_transform(mat, chaperone_mgr);
|
||||
}
|
||||
}
|
||||
|
||||
let xform = if self.universe == ETrackingUniverseOrigin::TrackingUniverseSeated {
|
||||
Affine3A::from_translation(Vec3::NEG_Y * height)
|
||||
} else {
|
||||
Affine3A::IDENTITY
|
||||
};
|
||||
|
||||
set_working_copy(&self.universe, chaperone_mgr, &xform);
|
||||
chaperone_mgr.commit_working_copy(EChaperoneConfigFile::EChaperoneConfigFile_Live);
|
||||
|
||||
if self.drag.is_some() {
|
||||
log::info!("Space drag interrupted by manual reset");
|
||||
self.drag = None;
|
||||
}
|
||||
if self.rotate.is_some() {
|
||||
log::info!("Space rotate interrupted by manual reset");
|
||||
self.rotate = None;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fix_floor(&mut self, chaperone_mgr: &mut ChaperoneSetupManager, input: &InputState) {
|
||||
let y1 = input.pointers[0].pose.translation.y;
|
||||
let y2 = input.pointers[1].pose.translation.y;
|
||||
self.offset.y += y1.min(y2) - 0.03;
|
||||
self.apply_offset(chaperone_mgr);
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.offset = Vec3A::ZERO;
|
||||
self.start_position = Vec3A::ZERO;
|
||||
}
|
||||
|
||||
fn apply_offset(&mut self, chaperone_mgr: &mut ChaperoneSetupManager) {
|
||||
let Some(mut zero_pose) =
|
||||
chaperone_mgr.get_working_standing_zero_pose_to_raw_tracking_pose()
|
||||
else {
|
||||
log::warn!("Can't space drag - failed to get zero pose");
|
||||
let Some(mut mat) = get_working_copy(&self.universe, chaperone_mgr) else {
|
||||
log::warn!("Can't fix floor - failed to get zero pose");
|
||||
return;
|
||||
};
|
||||
let offset = y1.min(y2) - 0.03;
|
||||
mat.translation.y += offset;
|
||||
|
||||
zero_pose.m[0][3] = self.offset.x;
|
||||
zero_pose.m[1][3] = self.offset.y;
|
||||
zero_pose.m[2][3] = self.offset.z;
|
||||
|
||||
chaperone_mgr.set_working_standing_zero_pose_to_raw_tracking_pose(&zero_pose);
|
||||
set_working_copy(&self.universe, chaperone_mgr, &mat);
|
||||
chaperone_mgr.commit_working_copy(EChaperoneConfigFile::EChaperoneConfigFile_Live);
|
||||
}
|
||||
|
||||
pub fn playspace_changed(
|
||||
&mut self,
|
||||
compositor_mgr: &mut CompositorManager,
|
||||
_chaperone_mgr: &mut ChaperoneSetupManager,
|
||||
) {
|
||||
let new_universe = compositor_mgr.get_tracking_space();
|
||||
if new_universe != self.universe {
|
||||
log::info!(
|
||||
"Playspace changed: {} -> {}",
|
||||
universe_str(&self.universe),
|
||||
universe_str(&new_universe)
|
||||
);
|
||||
self.universe = new_universe;
|
||||
}
|
||||
|
||||
if self.drag.is_some() {
|
||||
log::info!("Space drag interrupted by external change");
|
||||
self.drag = None;
|
||||
}
|
||||
if self.rotate.is_some() {
|
||||
log::info!("Space rotate interrupted by external change");
|
||||
self.rotate = None;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_universe(&self) -> ETrackingUniverseOrigin {
|
||||
self.universe.clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn universe_str(universe: &ETrackingUniverseOrigin) -> &'static str {
|
||||
match universe {
|
||||
ETrackingUniverseOrigin::TrackingUniverseSeated => "Seated",
|
||||
ETrackingUniverseOrigin::TrackingUniverseStanding => "Standing",
|
||||
ETrackingUniverseOrigin::TrackingUniverseRawAndUncalibrated => "Raw",
|
||||
}
|
||||
}
|
||||
|
||||
fn get_working_copy(
|
||||
universe: &ETrackingUniverseOrigin,
|
||||
chaperone_mgr: &mut ChaperoneSetupManager,
|
||||
) -> Option<Affine3A> {
|
||||
chaperone_mgr.revert_working_copy();
|
||||
let mat = match universe {
|
||||
ETrackingUniverseOrigin::TrackingUniverseStanding => {
|
||||
chaperone_mgr.get_working_standing_zero_pose_to_raw_tracking_pose()
|
||||
}
|
||||
_ => chaperone_mgr.get_working_seated_zero_pose_to_raw_tracking_pose(),
|
||||
};
|
||||
mat.map(|m| m.to_affine())
|
||||
}
|
||||
|
||||
fn set_working_copy(
|
||||
universe: &ETrackingUniverseOrigin,
|
||||
chaperone_mgr: &mut ChaperoneSetupManager,
|
||||
mat: &Affine3A,
|
||||
) {
|
||||
let mat = HmdMatrix34_t::from_affine(mat);
|
||||
match universe {
|
||||
ETrackingUniverseOrigin::TrackingUniverseStanding => {
|
||||
chaperone_mgr.set_working_standing_zero_pose_to_raw_tracking_pose(&mat)
|
||||
}
|
||||
_ => chaperone_mgr.set_working_seated_zero_pose_to_raw_tracking_pose(&mat),
|
||||
};
|
||||
}
|
||||
|
||||
fn apply_chaperone_offset(offset: Vec3A, chaperone_mgr: &mut ChaperoneSetupManager) {
|
||||
let mut quads = chaperone_mgr.get_live_collision_bounds_info();
|
||||
quads.iter_mut().for_each(|quad| {
|
||||
quad.vCorners.iter_mut().for_each(|corner| {
|
||||
corner.v[0] += offset.x;
|
||||
corner.v[2] += offset.z;
|
||||
});
|
||||
});
|
||||
chaperone_mgr.set_working_collision_bounds_info(quads.as_mut_slice());
|
||||
}
|
||||
|
||||
fn apply_chaperone_transform(transform: Affine3A, chaperone_mgr: &mut ChaperoneSetupManager) {
|
||||
let mut quads = chaperone_mgr.get_live_collision_bounds_info();
|
||||
quads.iter_mut().for_each(|quad| {
|
||||
quad.vCorners.iter_mut().for_each(|corner| {
|
||||
let coord = transform.transform_point3a(Vec3A::from_slice(&corner.v));
|
||||
corner.v[0] = coord.x;
|
||||
corner.v[2] = coord.z;
|
||||
});
|
||||
});
|
||||
chaperone_mgr.set_working_collision_bounds_info(quads.as_mut_slice());
|
||||
}
|
||||
@@ -4,9 +4,7 @@ use openxr as xr;
|
||||
use xr::OverlaySessionCreateFlagsEXTX;
|
||||
|
||||
pub(super) fn init_xr() -> Result<(xr::Instance, xr::SystemId), anyhow::Error> {
|
||||
let Ok(entry) = (unsafe { xr::Entry::load() }) else {
|
||||
bail!("OpenXR Loader not found.");
|
||||
};
|
||||
let entry = xr::Entry::linked();
|
||||
|
||||
let Ok(available_extensions) = entry.enumerate_extensions() else {
|
||||
bail!("Failed to enumerate OpenXR extensions.");
|
||||
|
||||
@@ -315,9 +315,10 @@ pub fn openxr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
|
||||
continue;
|
||||
};
|
||||
|
||||
let Some((state, backend)) = f(&mut app_state) else {
|
||||
let Some((mut state, backend)) = f(&mut app_state) else {
|
||||
continue;
|
||||
};
|
||||
state.birthframe = cur_frame;
|
||||
|
||||
overlays.add(OverlayData {
|
||||
state,
|
||||
@@ -326,9 +327,13 @@ pub fn openxr_run(running: Arc<AtomicBool>) -> Result<(), BackendError> {
|
||||
});
|
||||
}
|
||||
TaskType::DropOverlay(sel) => {
|
||||
let o = overlays.remove_by_selector(&sel);
|
||||
// set for deletion after all images are done showing
|
||||
delete_queue.push((o, cur_frame + 5));
|
||||
if let Some(o) = overlays.mut_by_selector(&sel) {
|
||||
if o.state.birthframe < cur_frame {
|
||||
let o = overlays.remove_by_selector(&sel);
|
||||
// set for deletion after all images are done showing
|
||||
delete_queue.push((o, cur_frame + 5));
|
||||
}
|
||||
}
|
||||
}
|
||||
TaskType::System(_task) => {
|
||||
// Not implemented
|
||||
|
||||
+5
-1
@@ -65,7 +65,11 @@ impl OscSender {
|
||||
match o.state.name.as_ref() {
|
||||
WATCH_NAME => has_wrist = true,
|
||||
KEYBOARD_NAME => has_keyboard = true,
|
||||
_ => num_overlays += 1,
|
||||
_ => {
|
||||
if o.state.interactable {
|
||||
num_overlays += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ pub struct OverlayState {
|
||||
pub relative_to: RelativeTo,
|
||||
pub primary_pointer: Option<usize>,
|
||||
pub interaction_transform: Affine2,
|
||||
pub birthframe: usize,
|
||||
}
|
||||
|
||||
impl Default for OverlayState {
|
||||
@@ -60,6 +61,7 @@ impl Default for OverlayState {
|
||||
transform: Affine3A::IDENTITY,
|
||||
primary_pointer: None,
|
||||
interaction_transform: Affine2::IDENTITY,
|
||||
birthframe: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-10
@@ -42,11 +42,11 @@ fn def_one() -> f32 {
|
||||
1.0
|
||||
}
|
||||
|
||||
fn def_half() -> f32 {
|
||||
pub fn def_half() -> f32 {
|
||||
0.5
|
||||
}
|
||||
|
||||
fn def_point7() -> f32 {
|
||||
pub fn def_point7() -> f32 {
|
||||
0.7
|
||||
}
|
||||
|
||||
@@ -165,14 +165,12 @@ where
|
||||
let file_name = FILES[config_type as usize];
|
||||
let maybe_override = config_io::load(file_name);
|
||||
|
||||
for yaml in [maybe_override.as_deref(), Some(fallback)].iter() {
|
||||
if let Some(yaml_data) = yaml {
|
||||
match serde_yaml::from_str::<T>(yaml_data) {
|
||||
Ok(d) => return d,
|
||||
Err(e) => {
|
||||
error!("Failed to parse {}, falling back to defaults.", file_name);
|
||||
error!("{}", e);
|
||||
}
|
||||
for yaml in [maybe_override.as_deref(), Some(fallback)].iter().flatten() {
|
||||
match serde_yaml::from_str::<T>(yaml) {
|
||||
Ok(d) => return d,
|
||||
Err(e) => {
|
||||
error!("Failed to parse {}, falling back to defaults.", file_name);
|
||||
error!("{}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+38
-35
@@ -10,14 +10,20 @@ use ash::vk::SubmitInfo;
|
||||
use smallvec::smallvec;
|
||||
|
||||
#[cfg(feature = "openvr")]
|
||||
use vulkano::{
|
||||
device::physical::PhysicalDeviceType, instance::InstanceCreateFlags,
|
||||
instance::InstanceExtensions,
|
||||
};
|
||||
use vulkano::{device::physical::PhysicalDeviceType, instance::InstanceCreateFlags};
|
||||
|
||||
#[cfg(feature = "openxr")]
|
||||
use {ash::vk, std::os::raw::c_void};
|
||||
|
||||
pub type Vert2Buf = Subbuffer<[Vert2Uv]>;
|
||||
pub type IndexBuf = Subbuffer<[u16]>;
|
||||
|
||||
pub type LegacyPipeline = WlxPipeline<WlxPipelineLegacy>;
|
||||
pub type DynamicPipeline = WlxPipeline<WlxPipelineDynamic>;
|
||||
|
||||
pub type LegacyPass = WlxPass<WlxPipelineLegacy>;
|
||||
pub type DynamicPass = WlxPass<WlxPipelineDynamic>;
|
||||
|
||||
use vulkano::{
|
||||
buffer::{
|
||||
allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo},
|
||||
@@ -47,7 +53,7 @@ use vulkano::{
|
||||
Image, ImageCreateInfo, ImageLayout, ImageTiling, ImageType, ImageUsage, SampleCount,
|
||||
SubresourceLayout,
|
||||
},
|
||||
instance::{Instance, InstanceCreateInfo},
|
||||
instance::{Instance, InstanceCreateInfo, InstanceExtensions},
|
||||
memory::{
|
||||
allocator::{
|
||||
AllocationCreateInfo, GenericMemoryAllocatorCreateInfo, MemoryAllocator,
|
||||
@@ -121,8 +127,8 @@ pub struct WlxGraphics {
|
||||
pub command_buffer_allocator: Arc<StandardCommandBufferAllocator>,
|
||||
pub descriptor_set_allocator: Arc<StandardDescriptorSetAllocator>,
|
||||
|
||||
pub quad_verts: Subbuffer<[Vert2Uv]>,
|
||||
pub quad_indices: Subbuffer<[u16]>,
|
||||
pub quad_verts: Vert2Buf,
|
||||
pub quad_indices: IndexBuf,
|
||||
|
||||
pub shared_shaders: RwLock<HashMap<&'static str, Arc<ShaderModule>>>,
|
||||
}
|
||||
@@ -477,7 +483,7 @@ impl WlxGraphics {
|
||||
|
||||
fn default_quad(
|
||||
memory_allocator: Arc<StandardMemoryAllocator>,
|
||||
) -> anyhow::Result<(Subbuffer<[Vert2Uv]>, Subbuffer<[u16]>)> {
|
||||
) -> anyhow::Result<(Vert2Buf, IndexBuf)> {
|
||||
let vertices = [
|
||||
Vert2Uv {
|
||||
in_pos: [0., 0.],
|
||||
@@ -535,7 +541,7 @@ impl WlxGraphics {
|
||||
y: f32,
|
||||
w: f32,
|
||||
h: f32,
|
||||
) -> anyhow::Result<Subbuffer<[Vert2Uv]>> {
|
||||
) -> anyhow::Result<Vert2Buf> {
|
||||
let rw = width;
|
||||
let rh = height;
|
||||
|
||||
@@ -707,8 +713,8 @@ impl WlxGraphics {
|
||||
frag: Arc<ShaderModule>,
|
||||
format: Format,
|
||||
blend: Option<AttachmentBlend>,
|
||||
) -> anyhow::Result<Arc<WlxPipeline<WlxPipelineLegacy>>> {
|
||||
Ok(Arc::new(WlxPipeline::<WlxPipelineLegacy>::new(
|
||||
) -> anyhow::Result<Arc<LegacyPipeline>> {
|
||||
Ok(Arc::new(LegacyPipeline::new(
|
||||
render_target,
|
||||
self.clone(),
|
||||
vert,
|
||||
@@ -727,8 +733,8 @@ impl WlxGraphics {
|
||||
blend: Option<AttachmentBlend>,
|
||||
initial_layout: ImageLayout,
|
||||
final_layout: ImageLayout,
|
||||
) -> anyhow::Result<Arc<WlxPipeline<WlxPipelineLegacy>>> {
|
||||
Ok(Arc::new(WlxPipeline::<WlxPipelineLegacy>::new_with_layout(
|
||||
) -> anyhow::Result<Arc<LegacyPipeline>> {
|
||||
Ok(Arc::new(LegacyPipeline::new_with_layout(
|
||||
render_target,
|
||||
self.clone(),
|
||||
vert,
|
||||
@@ -747,8 +753,8 @@ impl WlxGraphics {
|
||||
frag: Arc<ShaderModule>,
|
||||
format: Format,
|
||||
blend: Option<AttachmentBlend>,
|
||||
) -> anyhow::Result<Arc<WlxPipeline<WlxPipelineDynamic>>> {
|
||||
Ok(Arc::new(WlxPipeline::<WlxPipelineDynamic>::new(
|
||||
) -> anyhow::Result<Arc<DynamicPipeline>> {
|
||||
Ok(Arc::new(DynamicPipeline::new(
|
||||
self.clone(),
|
||||
vert,
|
||||
frag,
|
||||
@@ -844,10 +850,7 @@ pub struct WlxCommandBuffer {
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl WlxCommandBuffer {
|
||||
pub fn begin_render_pass(
|
||||
&mut self,
|
||||
pipeline: &WlxPipeline<WlxPipelineLegacy>,
|
||||
) -> anyhow::Result<()> {
|
||||
pub fn begin_render_pass(&mut self, pipeline: &LegacyPipeline) -> anyhow::Result<()> {
|
||||
self.command_buffer.begin_render_pass(
|
||||
RenderPassBeginInfo {
|
||||
clear_values: vec![Some([0.0, 0.0, 0.0, 0.0].into())],
|
||||
@@ -1034,11 +1037,11 @@ impl WlxPipeline<WlxPipelineDynamic> {
|
||||
pub fn create_pass(
|
||||
self: &Arc<Self>,
|
||||
dimensions: [f32; 2],
|
||||
vertex_buffer: Subbuffer<[Vert2Uv]>,
|
||||
index_buffer: Subbuffer<[u16]>,
|
||||
vertex_buffer: Vert2Buf,
|
||||
index_buffer: IndexBuf,
|
||||
descriptor_sets: Vec<Arc<DescriptorSet>>,
|
||||
) -> anyhow::Result<WlxPass<WlxPipelineDynamic>> {
|
||||
WlxPass::<WlxPipelineDynamic>::new(
|
||||
) -> anyhow::Result<DynamicPass> {
|
||||
DynamicPass::new(
|
||||
self.clone(),
|
||||
dimensions,
|
||||
vertex_buffer,
|
||||
@@ -1203,11 +1206,11 @@ impl WlxPipeline<WlxPipelineLegacy> {
|
||||
pub fn create_pass(
|
||||
self: &Arc<Self>,
|
||||
dimensions: [f32; 2],
|
||||
vertex_buffer: Subbuffer<[Vert2Uv]>,
|
||||
index_buffer: Subbuffer<[u16]>,
|
||||
vertex_buffer: Vert2Buf,
|
||||
index_buffer: IndexBuf,
|
||||
descriptor_sets: Vec<Arc<DescriptorSet>>,
|
||||
) -> anyhow::Result<WlxPass<WlxPipelineLegacy>> {
|
||||
WlxPass::<WlxPipelineLegacy>::new(
|
||||
) -> anyhow::Result<LegacyPass> {
|
||||
LegacyPass::new(
|
||||
self.clone(),
|
||||
dimensions,
|
||||
vertex_buffer,
|
||||
@@ -1281,18 +1284,18 @@ impl<D> WlxPipeline<D> {
|
||||
#[allow(dead_code)]
|
||||
pub struct WlxPass<D> {
|
||||
pipeline: Arc<WlxPipeline<D>>,
|
||||
vertex_buffer: Subbuffer<[Vert2Uv]>,
|
||||
index_buffer: Subbuffer<[u16]>,
|
||||
vertex_buffer: Vert2Buf,
|
||||
index_buffer: IndexBuf,
|
||||
descriptor_sets: Vec<Arc<DescriptorSet>>,
|
||||
pub command_buffer: Arc<CommandBuffer>,
|
||||
}
|
||||
|
||||
impl WlxPass<WlxPipelineLegacy> {
|
||||
fn new(
|
||||
pipeline: Arc<WlxPipeline<WlxPipelineLegacy>>,
|
||||
pipeline: Arc<LegacyPipeline>,
|
||||
dimensions: [f32; 2],
|
||||
vertex_buffer: Subbuffer<[Vert2Uv]>,
|
||||
index_buffer: Subbuffer<[u16]>,
|
||||
vertex_buffer: Vert2Buf,
|
||||
index_buffer: IndexBuf,
|
||||
descriptor_sets: Vec<Arc<DescriptorSet>>,
|
||||
) -> anyhow::Result<Self> {
|
||||
let viewport = Viewport {
|
||||
@@ -1349,10 +1352,10 @@ impl WlxPass<WlxPipelineLegacy> {
|
||||
|
||||
impl WlxPass<WlxPipelineDynamic> {
|
||||
fn new(
|
||||
pipeline: Arc<WlxPipeline<WlxPipelineDynamic>>,
|
||||
pipeline: Arc<DynamicPipeline>,
|
||||
dimensions: [f32; 2],
|
||||
vertex_buffer: Subbuffer<[Vert2Uv]>,
|
||||
index_buffer: Subbuffer<[u16]>,
|
||||
vertex_buffer: Vert2Buf,
|
||||
index_buffer: IndexBuf,
|
||||
descriptor_sets: Vec<Arc<DescriptorSet>>,
|
||||
) -> anyhow::Result<Self> {
|
||||
let viewport = Viewport {
|
||||
|
||||
@@ -19,7 +19,6 @@ use crate::{
|
||||
overlay::RelativeTo,
|
||||
},
|
||||
overlays::{
|
||||
mirror,
|
||||
toast::Toast,
|
||||
watch::{save_watch, WATCH_NAME},
|
||||
},
|
||||
@@ -173,7 +172,7 @@ pub struct ButtonData {
|
||||
}
|
||||
|
||||
pub fn modular_button_init(button: &mut ModularControl, data: &ButtonData) {
|
||||
button.state = Some(ModularData::Button(data.clone()));
|
||||
button.state = Some(ModularData::Button(Box::new(data.clone())));
|
||||
button.on_press = Some(modular_button_dn);
|
||||
button.on_release = Some(modular_button_up);
|
||||
button.on_scroll = Some(modular_button_scroll);
|
||||
@@ -475,7 +474,7 @@ fn run_watch(data: &WatchAction, app: &mut AppState) {
|
||||
app.tasks.enqueue(TaskType::Overlay(
|
||||
OverlaySelector::Name(WATCH_NAME.into()),
|
||||
Box::new(move |app, o| {
|
||||
o.spawn_rotation = o.spawn_rotation * rot;
|
||||
o.spawn_rotation *= rot;
|
||||
app.session.config.watch_rot = o.spawn_rotation.into();
|
||||
o.dirty = true;
|
||||
}),
|
||||
@@ -577,23 +576,12 @@ fn run_overlay(overlay: &OverlaySelector, action: &OverlayAction, app: &mut AppS
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland")]
|
||||
fn run_window(window: &Arc<str>, action: &WindowAction, app: &mut AppState) {
|
||||
use crate::overlays::custom;
|
||||
let selector = OverlaySelector::Name(window.clone());
|
||||
|
||||
match action {
|
||||
WindowAction::ShowMirror => {
|
||||
app.tasks.enqueue(TaskType::Overlay(
|
||||
selector,
|
||||
Box::new(|app, o| {
|
||||
o.want_visible = !o.want_visible;
|
||||
if o.recenter {
|
||||
o.show_hide = o.want_visible;
|
||||
o.reset(app, false);
|
||||
}
|
||||
}),
|
||||
));
|
||||
#[cfg(feature = "wayland")]
|
||||
app.tasks.enqueue(TaskType::CreateOverlay(
|
||||
OverlaySelector::Name(window.clone()),
|
||||
Box::new({
|
||||
@@ -602,22 +590,14 @@ fn run_window(window: &Arc<str>, action: &WindowAction, app: &mut AppState) {
|
||||
Toast::new("Check your desktop for popup.".into(), "".into())
|
||||
.with_sound(true)
|
||||
.submit(app);
|
||||
mirror::new_mirror(name.clone(), false, &app.session)
|
||||
crate::overlays::mirror::new_mirror(name.clone(), false, &app.session)
|
||||
}
|
||||
}),
|
||||
));
|
||||
#[cfg(not(feature = "wayland"))]
|
||||
log::warn!("Mirror not available without Wayland feature.");
|
||||
}
|
||||
WindowAction::ShowUi => {
|
||||
app.tasks.enqueue(TaskType::Overlay(
|
||||
selector,
|
||||
Box::new(|app, o| {
|
||||
o.want_visible = !o.want_visible;
|
||||
if o.recenter {
|
||||
o.show_hide = o.want_visible;
|
||||
o.reset(app, false);
|
||||
}
|
||||
}),
|
||||
));
|
||||
app.tasks.enqueue(TaskType::CreateOverlay(
|
||||
OverlaySelector::Name(window.clone()),
|
||||
Box::new({
|
||||
@@ -633,11 +613,6 @@ fn run_window(window: &Arc<str>, action: &WindowAction, app: &mut AppState) {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "wayland"))]
|
||||
fn run_action_window(_: Arc<str>, _: &WindowAction, _: &mut AppState) {
|
||||
log::warn!("Cannot run Window action without Wayland feature.");
|
||||
}
|
||||
|
||||
fn audio_thump(app: &mut AppState) {
|
||||
if let Some(handle) = app.audio.get_handle() {
|
||||
let wav = include_bytes!("../../res/380885.wav");
|
||||
|
||||
@@ -92,13 +92,13 @@ pub fn modular_label_init(label: &mut ModularControl, content: &LabelContent) {
|
||||
child: None,
|
||||
}),
|
||||
LabelContent::Static { text } => {
|
||||
label.set_text(&text);
|
||||
label.set_text(text);
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(state) = state {
|
||||
label.state = Some(ModularData::Label(state));
|
||||
label.state = Some(ModularData::Label(Box::new(state)));
|
||||
label.on_update = Some(label_update);
|
||||
}
|
||||
}
|
||||
@@ -107,7 +107,7 @@ pub(super) fn label_update(control: &mut ModularControl, _: &mut (), app: &mut A
|
||||
let ModularData::Label(data) = control.state.as_mut().unwrap() else {
|
||||
panic!("Label control has no state");
|
||||
};
|
||||
match data {
|
||||
match data.as_mut() {
|
||||
LabelData::Battery {
|
||||
device,
|
||||
low_threshold,
|
||||
|
||||
+13
-13
@@ -70,7 +70,7 @@ pub enum ModularElement {
|
||||
bg_color: Arc<str>,
|
||||
text: Arc<str>,
|
||||
#[serde(flatten)]
|
||||
data: ButtonData,
|
||||
data: Box<ButtonData>,
|
||||
},
|
||||
/// Convenience type to save you from having to create a bunch of labels
|
||||
BatteryList {
|
||||
@@ -90,7 +90,7 @@ pub enum ModularElement {
|
||||
bg_color: Arc<str>,
|
||||
layout: ListLayout,
|
||||
#[serde(flatten)]
|
||||
template: OverlayListTemplate,
|
||||
template: Box<OverlayListTemplate>,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -107,8 +107,8 @@ pub enum ListLayout {
|
||||
}
|
||||
|
||||
pub enum ModularData {
|
||||
Label(LabelData),
|
||||
Button(ButtonData),
|
||||
Label(Box<LabelData>),
|
||||
Button(Box<ButtonData>),
|
||||
}
|
||||
|
||||
pub fn modular_canvas(
|
||||
@@ -130,7 +130,7 @@ pub fn modular_canvas(
|
||||
rect: [x, y, w, h],
|
||||
bg_color,
|
||||
} => {
|
||||
canvas.bg_color = color_parse(&bg_color).unwrap_or(FALLBACK_COLOR);
|
||||
canvas.bg_color = color_parse(bg_color).unwrap_or(FALLBACK_COLOR);
|
||||
canvas.panel(*x, *y, *w, *h);
|
||||
}
|
||||
ModularElement::Label {
|
||||
@@ -140,9 +140,9 @@ pub fn modular_canvas(
|
||||
data,
|
||||
} => {
|
||||
canvas.font_size = *font_size;
|
||||
canvas.fg_color = color_parse(&fg_color).unwrap_or(FALLBACK_COLOR);
|
||||
let mut label = canvas.label(*x, *y, *w, *h, empty_str.clone());
|
||||
modular_label_init(&mut label, data);
|
||||
canvas.fg_color = color_parse(fg_color).unwrap_or(FALLBACK_COLOR);
|
||||
let label = canvas.label(*x, *y, *w, *h, empty_str.clone());
|
||||
modular_label_init(label, data);
|
||||
}
|
||||
ModularElement::Button {
|
||||
rect: [x, y, w, h],
|
||||
@@ -152,8 +152,8 @@ pub fn modular_canvas(
|
||||
text,
|
||||
data,
|
||||
} => {
|
||||
canvas.bg_color = color_parse(&bg_color).unwrap_or(FALLBACK_COLOR);
|
||||
canvas.fg_color = color_parse(&fg_color).unwrap_or(FALLBACK_COLOR);
|
||||
canvas.bg_color = color_parse(bg_color).unwrap_or(FALLBACK_COLOR);
|
||||
canvas.fg_color = color_parse(fg_color).unwrap_or(FALLBACK_COLOR);
|
||||
canvas.font_size = *font_size;
|
||||
let button = canvas.button(*x, *y, *w, *h, text.clone());
|
||||
modular_button_init(button, data);
|
||||
@@ -177,7 +177,7 @@ pub fn modular_canvas(
|
||||
ListLayout::Vertical => (*w, *h / num_buttons),
|
||||
};
|
||||
|
||||
let fg_color = color_parse(&fg_color).unwrap_or(FALLBACK_COLOR);
|
||||
let fg_color = color_parse(fg_color).unwrap_or(FALLBACK_COLOR);
|
||||
canvas.font_size = *font_size;
|
||||
canvas.fg_color = fg_color;
|
||||
|
||||
@@ -225,8 +225,8 @@ pub fn modular_canvas(
|
||||
ListLayout::Vertical => (*w, *h / num_buttons),
|
||||
};
|
||||
|
||||
canvas.bg_color = color_parse(&bg_color).unwrap_or(FALLBACK_COLOR);
|
||||
canvas.fg_color = color_parse(&fg_color).unwrap_or(FALLBACK_COLOR);
|
||||
canvas.bg_color = color_parse(bg_color).unwrap_or(FALLBACK_COLOR);
|
||||
canvas.fg_color = color_parse(fg_color).unwrap_or(FALLBACK_COLOR);
|
||||
canvas.font_size = *font_size;
|
||||
|
||||
for screen in state.screens.iter() {
|
||||
|
||||
+8
-1
@@ -17,7 +17,14 @@ pub fn initialize() -> Box<dyn HidProvider> {
|
||||
return Box::new(uinput);
|
||||
}
|
||||
log::error!("Could not create uinput provider. Keyboard/Mouse input will not work!");
|
||||
log::error!("Check if you're in `input` group: `id -nG`");
|
||||
log::error!("To check if you're in input group, run: id -nG");
|
||||
if let Ok(user) = std::env::var("USER") {
|
||||
log::error!(
|
||||
"To add yourself to the input group, run: sudo usermod -aG input {}",
|
||||
user
|
||||
);
|
||||
log::error!("After adding yourself to the input group, you will need to reboot.");
|
||||
}
|
||||
Box::new(DummyProvider {})
|
||||
}
|
||||
|
||||
|
||||
+34
-6
@@ -42,9 +42,9 @@ struct Args {
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args = Args::parse();
|
||||
if let Some(log_to) = args.log_to {
|
||||
if let Some(ref log_to) = args.log_to {
|
||||
flexi_logger::Logger::try_with_env_or_str("info")?
|
||||
.log_to_file(FileSpec::default().directory(&log_to))
|
||||
.log_to_file(FileSpec::default().directory(log_to))
|
||||
.log_to_stdout()
|
||||
.start()?;
|
||||
println!("Logging to: {}", &log_to);
|
||||
@@ -72,16 +72,16 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
});
|
||||
|
||||
auto_run(running, args.openvr, args.openxr);
|
||||
auto_run(running, args);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn auto_run(running: Arc<AtomicBool>, openvr: bool, openxr: bool) {
|
||||
fn auto_run(running: Arc<AtomicBool>, args: Args) {
|
||||
use backend::common::BackendError;
|
||||
|
||||
#[cfg(feature = "openxr")]
|
||||
if !openvr {
|
||||
if !args_get_openvr(&args) {
|
||||
use crate::backend::openxr::openxr_run;
|
||||
match openxr_run(running.clone()) {
|
||||
Ok(()) => return,
|
||||
@@ -94,7 +94,7 @@ fn auto_run(running: Arc<AtomicBool>, openvr: bool, openxr: bool) {
|
||||
}
|
||||
|
||||
#[cfg(feature = "openvr")]
|
||||
if !openxr {
|
||||
if !args_get_openxr(&args) {
|
||||
use crate::backend::openvr::openvr_run;
|
||||
match openvr_run(running.clone()) {
|
||||
Ok(()) => return,
|
||||
@@ -107,4 +107,32 @@ fn auto_run(running: Arc<AtomicBool>, openvr: bool, openxr: bool) {
|
||||
}
|
||||
|
||||
log::error!("No more backends to try");
|
||||
|
||||
#[cfg(not(any(feature = "openvr", feature = "openxr")))]
|
||||
compile_error!("No VR support! Enable either openvr or openxr features!");
|
||||
|
||||
#[cfg(not(any(feature = "wayland", feature = "x11")))]
|
||||
compile_error!("No desktop support! Enable either wayland or x11 features!");
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn args_get_openvr(_args: &Args) -> bool {
|
||||
#[cfg(feature = "openvr")]
|
||||
let ret = _args.openvr;
|
||||
|
||||
#[cfg(not(feature = "openvr"))]
|
||||
let ret = false;
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn args_get_openxr(_args: &Args) -> bool {
|
||||
#[cfg(feature = "openxr")]
|
||||
let ret = _args.openxr;
|
||||
|
||||
#[cfg(not(feature = "openxr"))]
|
||||
let ret = false;
|
||||
|
||||
ret
|
||||
}
|
||||
+45
-11
@@ -16,7 +16,6 @@ use wlx_capture::{
|
||||
DrmFormat, MouseMeta, WlxFrame, DRM_FORMAT_ABGR8888, DRM_FORMAT_ARGB8888,
|
||||
DRM_FORMAT_XBGR8888, DRM_FORMAT_XRGB8888,
|
||||
},
|
||||
wayland::wayland_client::protocol::wl_output::Transform,
|
||||
WlxCapture,
|
||||
};
|
||||
|
||||
@@ -27,7 +26,7 @@ use {
|
||||
std::{collections::HashMap, error::Error, f32::consts::PI, ops::Deref, path::PathBuf},
|
||||
wlx_capture::{
|
||||
pipewire::{pipewire_select_screen, PipewireCapture},
|
||||
wayland::{WlxClient, WlxOutput},
|
||||
wayland::{wayland_client::protocol::wl_output, WlxClient, WlxOutput},
|
||||
wlr_dmabuf::WlrDmabufCapture,
|
||||
wlr_screencopy::WlrScreencopyCapture,
|
||||
},
|
||||
@@ -49,6 +48,8 @@ use crate::{
|
||||
state::{AppSession, AppState},
|
||||
};
|
||||
|
||||
const CURSOR_SIZE: f32 = 16. / 1440.;
|
||||
|
||||
static DRM_FORMATS: once_cell::sync::OnceCell<Vec<DrmFormat>> = once_cell::sync::OnceCell::new();
|
||||
|
||||
pub struct ScreenInteractionHandler {
|
||||
@@ -208,18 +209,21 @@ impl ScreenPipeline {
|
||||
cmd.run_ref(&pass)?;
|
||||
|
||||
if let (Some(mouse), Some(mouse_view)) = (mouse, self.mouse.clone()) {
|
||||
let size = CURSOR_SIZE * self.extentf[1];
|
||||
let half_size = size * 0.5;
|
||||
|
||||
let vertex_buffer = app.graphics.upload_verts(
|
||||
self.extentf[0],
|
||||
self.extentf[1],
|
||||
mouse.x * self.extentf[0] - 2.,
|
||||
mouse.y * self.extentf[1] - 2.,
|
||||
4.0,
|
||||
4.0,
|
||||
mouse.x * self.extentf[0] - half_size,
|
||||
mouse.y * self.extentf[1] - half_size,
|
||||
size,
|
||||
size,
|
||||
)?;
|
||||
|
||||
let set0 = self
|
||||
.pipeline
|
||||
.uniform_sampler(0, mouse_view.clone(), Filter::Linear)?;
|
||||
.uniform_sampler(0, mouse_view.clone(), Filter::Nearest)?;
|
||||
|
||||
let pass = self.pipeline.create_pass(
|
||||
self.extentf,
|
||||
@@ -566,14 +570,16 @@ where
|
||||
interaction: Box::new(ScreenInteractionHandler::new(
|
||||
vec2(output.logical_pos.0 as f32, output.logical_pos.1 as f32),
|
||||
vec2(output.logical_size.0 as f32, output.logical_size.1 as f32),
|
||||
output.transform,
|
||||
output.transform.into(),
|
||||
)),
|
||||
});
|
||||
|
||||
let axis = Vec3::new(0., 0., 1.);
|
||||
|
||||
let transform = output.transform.into();
|
||||
|
||||
let angle = if session.config.upright_screen_fix {
|
||||
match output.transform {
|
||||
match transform {
|
||||
Transform::_90 | Transform::Flipped90 => PI / 2.,
|
||||
Transform::_180 | Transform::Flipped180 => PI,
|
||||
Transform::_270 | Transform::Flipped270 => -PI / 2.,
|
||||
@@ -584,7 +590,7 @@ where
|
||||
};
|
||||
|
||||
let center = Vec2 { x: 0.5, y: 0.5 };
|
||||
let interaction_transform = match output.transform {
|
||||
let interaction_transform = match transform {
|
||||
Transform::_90 | Transform::Flipped90 => Affine2::from_cols(
|
||||
Vec2::NEG_Y * (output.size.0 as f32 / output.size.1 as f32),
|
||||
Vec2::NEG_X,
|
||||
@@ -797,11 +803,39 @@ where
|
||||
Ok((overlays, extent))
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub enum Transform {
|
||||
Normal,
|
||||
_90,
|
||||
_180,
|
||||
_270,
|
||||
Flipped90,
|
||||
Flipped180,
|
||||
Flipped270,
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland")]
|
||||
impl From<wl_output::Transform> for Transform {
|
||||
fn from(t: wl_output::Transform) -> Transform {
|
||||
match t {
|
||||
wl_output::Transform::Normal => Transform::Normal,
|
||||
wl_output::Transform::_90 => Transform::_90,
|
||||
wl_output::Transform::_180 => Transform::_180,
|
||||
wl_output::Transform::_270 => Transform::_270,
|
||||
wl_output::Transform::Flipped => Transform::Flipped180,
|
||||
wl_output::Transform::Flipped90 => Transform::Flipped90,
|
||||
wl_output::Transform::Flipped180 => Transform::Flipped180,
|
||||
wl_output::Transform::Flipped270 => Transform::Flipped270,
|
||||
_ => Transform::Normal,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn extent_from_res(res: (i32, i32)) -> [u32; 3] {
|
||||
// screens above a certain resolution will have severe aliasing
|
||||
|
||||
// TODO make dynamic. maybe don't go above HMD resolution?
|
||||
let w = res.0.min(1920) as u32;
|
||||
let w = res.0.min(2560) as u32;
|
||||
let h = (res.1 as f32 / res.0 as f32 * w as f32) as u32;
|
||||
[w, h, 1]
|
||||
}
|
||||
+13
-3
@@ -4,7 +4,9 @@ use std::path::PathBuf;
|
||||
|
||||
use crate::{
|
||||
backend::overlay::{ui_transform, OverlayData, OverlayState, RelativeTo},
|
||||
config::{def_left, def_watch_pos, def_watch_rot, load_known_yaml, ConfigType},
|
||||
config::{
|
||||
def_half, def_left, def_point7, def_watch_pos, def_watch_rot, load_known_yaml, ConfigType,
|
||||
},
|
||||
config_io,
|
||||
gui::modular::{modular_canvas, ModularUiConfig},
|
||||
state::{AppState, LeftRight},
|
||||
@@ -78,6 +80,12 @@ pub struct WatchConf {
|
||||
|
||||
#[serde(default = "def_left")]
|
||||
pub watch_hand: LeftRight,
|
||||
|
||||
#[serde(default = "def_half")]
|
||||
pub watch_view_angle_min: f32,
|
||||
|
||||
#[serde(default = "def_point7")]
|
||||
pub watch_view_angle_max: f32,
|
||||
}
|
||||
|
||||
fn get_config_path() -> PathBuf {
|
||||
@@ -87,9 +95,11 @@ fn get_config_path() -> PathBuf {
|
||||
}
|
||||
pub fn save_watch(app: &mut AppState) -> anyhow::Result<()> {
|
||||
let conf = WatchConf {
|
||||
watch_pos: app.session.config.watch_pos.clone(),
|
||||
watch_rot: app.session.config.watch_rot.clone(),
|
||||
watch_pos: app.session.config.watch_pos,
|
||||
watch_rot: app.session.config.watch_rot,
|
||||
watch_hand: app.session.config.watch_hand,
|
||||
watch_view_angle_min: app.session.config.watch_view_angle_min,
|
||||
watch_view_angle_max: app.session.config.watch_view_angle_max,
|
||||
};
|
||||
|
||||
let yaml = serde_yaml::to_string(&conf)?;
|
||||
|
||||
@@ -40,6 +40,11 @@
|
||||
"type": "boolean",
|
||||
"requirement": "optional"
|
||||
},
|
||||
{
|
||||
"name": "/actions/default/in/SpaceRotate",
|
||||
"type": "boolean",
|
||||
"requirement": "optional"
|
||||
},
|
||||
{
|
||||
"name": "/actions/default/in/LeftHand",
|
||||
"type": "pose",
|
||||
|
||||
+16
-7
@@ -270,10 +270,13 @@ elements:
|
||||
fg_color: "#ffffff"
|
||||
bg_color: "#707070"
|
||||
text: "Show/Hide"
|
||||
click_down:
|
||||
click_down: # ToggleVisible if exists, else create
|
||||
- type: Overlay
|
||||
target: M1
|
||||
action: ToggleVisible # only fires if overlay exists
|
||||
- type: Window
|
||||
target: M1
|
||||
action: ShowMirror
|
||||
action: ShowMirror # only fires if not exists
|
||||
|
||||
- type: Button
|
||||
rect: [185, 270, 60, 30]
|
||||
@@ -311,6 +314,9 @@ elements:
|
||||
bg_color: "#707070"
|
||||
text: "Show/Hide"
|
||||
click_down:
|
||||
- type: Overlay
|
||||
target: M2
|
||||
action: ToggleVisible
|
||||
- type: Window
|
||||
target: M2
|
||||
action: ShowMirror
|
||||
@@ -351,6 +357,9 @@ elements:
|
||||
bg_color: "#707070"
|
||||
text: "Show/Hide"
|
||||
click_down:
|
||||
- type: Overlay
|
||||
target: M3
|
||||
action: ToggleVisible
|
||||
- type: Window
|
||||
target: M3
|
||||
action: ShowMirror
|
||||
@@ -509,14 +518,14 @@ elements:
|
||||
bg_color: "#c0c0c0"
|
||||
|
||||
- type: Label
|
||||
rect: [325, 480, 90, 24]
|
||||
rect: [325, 490, 90, 24]
|
||||
font_size: 18
|
||||
fg_color: "#ffffff"
|
||||
source: Static
|
||||
text: Notifications
|
||||
|
||||
- type: Button
|
||||
rect: [330, 495, 220, 30]
|
||||
rect: [330, 505, 220, 30]
|
||||
font_size: 12
|
||||
fg_color: "#ffffff"
|
||||
bg_color: "#606020"
|
||||
@@ -526,7 +535,7 @@ elements:
|
||||
action: ToggleNotifications
|
||||
|
||||
- type: Button
|
||||
rect: [330, 545, 220, 30]
|
||||
rect: [330, 555, 220, 30]
|
||||
font_size: 12
|
||||
fg_color: "#ffffff"
|
||||
bg_color: "#606020"
|
||||
@@ -536,11 +545,11 @@ elements:
|
||||
action: ToggleNotificationSounds
|
||||
|
||||
- type: Panel
|
||||
rect: [50, 595, 500, 1]
|
||||
rect: [50, 605, 500, 1]
|
||||
bg_color: "#c0c0c0"
|
||||
|
||||
- type: Button
|
||||
rect: [330, 615, 220, 30]
|
||||
rect: [330, 625, 220, 30]
|
||||
font_size: 12
|
||||
fg_color: "#ffffff"
|
||||
bg_color: "#206060"
|
||||
|
||||
+5
-2
@@ -18,10 +18,13 @@ elements:
|
||||
bg_color: "#808040"
|
||||
fg_color: "#ffffff"
|
||||
text: "C"
|
||||
click_up:
|
||||
click_up: # destroy if exists, otherwise create
|
||||
- type: Window
|
||||
target: settings
|
||||
action: ShowUi
|
||||
action: ShowUi # only triggers if not exists
|
||||
- type: Window
|
||||
target: settings
|
||||
action: Destroy # only triggers if exists since before current frame
|
||||
|
||||
# Keyboard button
|
||||
- type: Button
|
||||
|
||||
@@ -94,6 +94,12 @@ pub mod frag_screen {
|
||||
void main()
|
||||
{
|
||||
out_color = texture(in_texture, in_uv);
|
||||
|
||||
// linear to srgb
|
||||
bvec4 cutoff = lessThan(out_color, vec4(0.0031308));
|
||||
vec4 higher = (pow(out_color, vec4(0.41666)) * vec4(1.055)) - vec4(0.055);
|
||||
vec4 lower = out_color*vec4(12.92);
|
||||
out_color = mix(higher, lower, cutoff);
|
||||
out_color.a = 1.0;
|
||||
}
|
||||
",
|
||||
|
||||
Reference in new issue
Block a user