Files
wayvr/src/backend/common.rs
galister e7b415ae4e clippy
2024-02-20 20:55:14 +01:00

257 lines
6.9 KiB
Rust

use std::{
collections::{BinaryHeap, VecDeque},
sync::Arc,
time::Instant,
};
#[cfg(feature = "openxr")]
use openxr as xr;
use glam::{Affine3A, Vec2, Vec3A};
use idmap::IdMap;
use thiserror::Error;
use crate::{
overlays::{
keyboard::create_keyboard,
toast::Toast,
watch::{create_watch, WATCH_NAME, WATCH_SCALE},
},
state::AppState,
};
use super::overlay::{OverlayBackend, OverlayData, OverlayState};
#[derive(Error, Debug)]
pub enum BackendError {
#[error("backend not supported")]
NotSupported,
#[cfg(feature = "openxr")]
#[error("openxr error {0}")]
OpenXrError(#[from] xr::sys::Result),
#[error("shutdown")]
Shutdown,
#[error("restart")]
Restart,
#[error("fatal")]
Fatal(#[from] anyhow::Error),
}
pub struct OverlayContainer<T>
where
T: Default,
{
overlays: IdMap<usize, OverlayData<T>>,
pub extent: Vec2,
}
impl<T> OverlayContainer<T>
where
T: Default,
{
pub fn new(app: &mut AppState) -> anyhow::Result<Self> {
let mut overlays = IdMap::new();
let (screens, extent) = if std::env::var("WAYLAND_DISPLAY").is_ok() {
crate::overlays::screen::get_screens_wayland(&app.session)?
} else {
crate::overlays::screen::get_screens_x11(&app.session)?
};
let mut watch = create_watch::<T>(app, &screens)?;
watch.state.want_visible = true;
overlays.insert(watch.state.id, watch);
let mut keyboard = create_keyboard(app)?;
keyboard.state.show_hide = true;
keyboard.state.want_visible = false;
overlays.insert(keyboard.state.id, keyboard);
let mut show_screens = app.session.config.show_screens.clone();
if show_screens.is_empty() {
screens.first().map(|s| {
show_screens.push(s.state.name.clone());
});
}
for mut screen in screens {
if show_screens.contains(&screen.state.name) {
screen.state.show_hide = true;
screen.state.want_visible = false;
}
overlays.insert(screen.state.id, screen);
}
Ok(Self { overlays, extent })
}
pub fn mut_by_selector(&mut self, selector: &OverlaySelector) -> Option<&mut OverlayData<T>> {
match selector {
OverlaySelector::Id(id) => self.mut_by_id(*id),
OverlaySelector::Name(name) => self.mut_by_name(name),
}
}
pub fn drop_by_selector(&mut self, selector: &OverlaySelector) {
match selector {
OverlaySelector::Id(id) => {
self.overlays.remove(id);
}
OverlaySelector::Name(name) => {
let id = self
.overlays
.iter()
.find(|(_, o)| *o.state.name == **name)
.map(|(id, _)| *id);
id.and_then(|id| self.overlays.remove(id));
}
};
}
pub fn get_by_id(&mut self, id: usize) -> Option<&OverlayData<T>> {
self.overlays.get(id)
}
pub fn mut_by_id(&mut self, id: usize) -> Option<&mut OverlayData<T>> {
self.overlays.get_mut(id)
}
pub fn get_by_name<'a>(&'a mut self, name: &str) -> Option<&'a OverlayData<T>> {
self.overlays.values().find(|o| *o.state.name == *name)
}
pub fn mut_by_name<'a>(&'a mut self, name: &str) -> Option<&'a mut OverlayData<T>> {
self.overlays.values_mut().find(|o| *o.state.name == *name)
}
pub fn iter(&self) -> impl Iterator<Item = &'_ OverlayData<T>> {
self.overlays.values()
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &'_ mut OverlayData<T>> {
self.overlays.values_mut()
}
pub fn add(&mut self, overlay: OverlayData<T>) {
self.overlays.insert(overlay.state.id, overlay);
}
pub fn show_hide(&mut self, app: &mut AppState) {
let any_shown = self
.overlays
.values()
.any(|o| o.state.show_hide && o.state.want_visible);
self.overlays.values_mut().for_each(|o| {
if o.state.show_hide {
o.state.want_visible = !any_shown;
if o.state.want_visible && o.state.recenter {
o.state.reset(app, false);
}
}
// toggle watch back on if it was hidden
if !any_shown && *o.state.name == *WATCH_NAME {
o.state.spawn_scale = WATCH_SCALE * app.session.config.watch_scale;
}
})
}
}
#[derive(Clone)]
pub enum OverlaySelector {
Id(usize),
Name(Arc<str>),
}
struct AppTask {
pub not_before: Instant,
pub task: TaskType,
}
impl PartialEq<AppTask> for AppTask {
fn eq(&self, other: &Self) -> bool {
self.not_before == other.not_before
}
}
impl PartialOrd<AppTask> for AppTask {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.not_before.cmp(&other.not_before).reverse())
}
}
impl Eq for AppTask {}
impl Ord for AppTask {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.not_before.cmp(&other.not_before).reverse()
}
}
pub enum TaskType {
Global(Box<dyn FnOnce(&mut AppState) + Send>),
Overlay(
OverlaySelector,
Box<dyn FnOnce(&mut AppState, &mut OverlayState) + Send>,
),
CreateOverlay(
OverlaySelector,
Box<dyn FnOnce(&mut AppState) -> Option<(OverlayState, Box<dyn OverlayBackend>)> + Send>,
),
DropOverlay(OverlaySelector),
Toast(Toast),
}
pub struct TaskContainer {
tasks: BinaryHeap<AppTask>,
}
impl TaskContainer {
pub fn new() -> Self {
Self {
tasks: BinaryHeap::new(),
}
}
pub fn enqueue(&mut self, task: TaskType) {
self.tasks.push(AppTask {
not_before: Instant::now(),
task,
});
}
pub fn enqueue_at(&mut self, task: TaskType, not_before: Instant) {
self.tasks.push(AppTask { not_before, task });
}
pub fn retrieve_due(&mut self, dest_buf: &mut VecDeque<TaskType>) {
let now = Instant::now();
while let Some(task) = self.tasks.peek() {
if task.not_before > now {
break;
}
// Safe unwrap because we peeked.
dest_buf.push_back(self.tasks.pop().unwrap().task);
}
}
}
pub fn raycast(
source: &Affine3A,
source_fwd: Vec3A,
plane: &Affine3A,
plane_norm: Vec3A,
) -> Option<(Vec3A, f32)> {
let plane_normal = plane.transform_vector3a(plane_norm);
let ray_dir = source.transform_vector3a(source_fwd);
let d = plane.translation.dot(-plane_normal);
let dist = -(d + source.translation.dot(plane_normal)) / ray_dir.dot(plane_normal);
if dist < 0.0 {
// plane is behind the caster
return None;
}
let hit_pos = source.translation + ray_dir * dist;
Some((hit_pos, dist))
}