Files
wayvr/src/overlays/watch.rs
2024-04-04 20:06:53 +09:00

120 lines
3.5 KiB
Rust

use glam::{Quat, Vec3A};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use crate::{
backend::overlay::{ui_transform, OverlayData, OverlayState, RelativeTo},
config::{
def_half, def_left, def_point7, def_watch_pos, def_watch_rot, load_known_yaml, ConfigType,
},
config_io,
gui::{
modular::{modular_canvas, ModularData, ModularUiConfig},
Canvas,
},
state::{AppState, LeftRight},
};
pub const WATCH_NAME: &str = "watch";
pub fn create_watch<O>(state: &AppState) -> anyhow::Result<OverlayData<O>>
where
O: Default,
{
let config = load_known_yaml::<ModularUiConfig>(ConfigType::Watch);
let relative_to = RelativeTo::Hand(state.session.config.watch_hand as usize);
Ok(OverlayData {
state: OverlayState {
name: WATCH_NAME.into(),
want_visible: true,
interactable: true,
spawn_scale: config.width,
spawn_point: Vec3A::from_slice(&state.session.config.watch_pos),
spawn_rotation: Quat::from_slice(&state.session.config.watch_rot),
interaction_transform: ui_transform(&config.size),
relative_to,
..Default::default()
},
backend: Box::new(create_watch_canvas(Some(config), state)?),
..Default::default()
})
}
pub fn create_watch_canvas(
config: Option<ModularUiConfig>,
state: &AppState,
) -> anyhow::Result<Canvas<(), ModularData>> {
let config = config.unwrap_or_else(|| load_known_yaml::<ModularUiConfig>(ConfigType::Watch));
modular_canvas(&config.size, &config.elements, state)
}
pub fn watch_fade<D>(app: &mut AppState, watch: &mut OverlayData<D>)
where
D: Default,
{
if watch.state.saved_scale.is_some_and(|s| s < f32::EPSILON) {
watch.state.want_visible = false;
return;
}
let to_hmd = (watch.state.transform.translation - app.input_state.hmd.translation).normalize();
let watch_normal = watch
.state
.transform
.transform_vector3a(Vec3A::NEG_Z)
.normalize();
let dot = to_hmd.dot(watch_normal);
if dot < app.session.config.watch_view_angle_min {
watch.state.want_visible = false;
} else {
watch.state.want_visible = true;
watch.state.alpha = (dot - app.session.config.watch_view_angle_min)
/ (app.session.config.watch_view_angle_max - app.session.config.watch_view_angle_min);
watch.state.alpha += 0.1;
watch.state.alpha = watch.state.alpha.clamp(0., 1.);
}
}
#[derive(Deserialize, Serialize)]
pub struct WatchConf {
#[serde(default = "def_watch_pos")]
pub watch_pos: [f32; 3],
#[serde(default = "def_watch_rot")]
pub watch_rot: [f32; 4],
#[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 {
let mut path = config_io::get_conf_d_path();
path.push("watch_state.yaml");
path
}
pub fn save_watch(app: &mut AppState) -> anyhow::Result<()> {
let conf = WatchConf {
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)?;
std::fs::write(get_config_path(), yaml)?;
Ok(())
}