bar + overlaybackend refactor
This commit is contained in:
@@ -13,11 +13,10 @@ use crate::{
|
||||
overlays::{
|
||||
anchor::create_anchor,
|
||||
keyboard::{KEYBOARD_NAME, builder::create_keyboard},
|
||||
screen::WlxClientAlias,
|
||||
screen::create_screens,
|
||||
watch::{WATCH_NAME, create_watch},
|
||||
},
|
||||
state::AppState,
|
||||
subsystem::hid::{get_keymap_wl, get_keymap_x11},
|
||||
};
|
||||
|
||||
use super::overlay::{OverlayData, OverlayID};
|
||||
@@ -37,22 +36,11 @@ pub enum BackendError {
|
||||
Fatal(#[from] anyhow::Error),
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland")]
|
||||
fn create_wl_client() -> Option<WlxClientAlias> {
|
||||
wlx_capture::wayland::WlxClient::new()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "wayland"))]
|
||||
fn create_wl_client() -> Option<WlxClientAlias> {
|
||||
None
|
||||
}
|
||||
|
||||
pub struct OverlayContainer<T>
|
||||
where
|
||||
T: Default,
|
||||
{
|
||||
overlays: IdMap<usize, OverlayData<T>>,
|
||||
wl: Option<WlxClientAlias>,
|
||||
}
|
||||
|
||||
impl<T> OverlayContainer<T>
|
||||
@@ -62,55 +50,35 @@ where
|
||||
pub fn new(app: &mut AppState, headless: bool) -> anyhow::Result<Self> {
|
||||
let mut overlays = IdMap::new();
|
||||
let mut show_screens = app.session.config.show_screens.clone();
|
||||
let mut wl = None;
|
||||
let mut keymap = None;
|
||||
|
||||
app.screens.clear();
|
||||
let mut maybe_keymap = None;
|
||||
|
||||
if headless {
|
||||
log::info!("Running in headless mode; keyboard will be en-US");
|
||||
} else {
|
||||
wl = create_wl_client();
|
||||
|
||||
let data = if let Some(wl) = wl.as_mut() {
|
||||
log::info!("Wayland detected.");
|
||||
keymap = get_keymap_wl()
|
||||
.map_err(|f| log::warn!("Could not load keyboard layout: {f}"))
|
||||
.ok();
|
||||
crate::overlays::screen::create_screens_wayland(wl, app)
|
||||
} else {
|
||||
log::info!("Wayland not detected, assuming X11.");
|
||||
keymap = get_keymap_x11()
|
||||
.map_err(|f| log::warn!("Could not load keyboard layout: {f}"))
|
||||
.ok();
|
||||
match crate::overlays::screen::create_screens_x11pw(app) {
|
||||
Ok(data) => data,
|
||||
Err(e) => {
|
||||
log::info!("Will not use X11 PipeWire capture: {e:?}");
|
||||
crate::overlays::screen::create_screens_xshm(app)?
|
||||
match create_screens(app) {
|
||||
Ok((data, keymap)) => {
|
||||
if show_screens.is_empty() {
|
||||
if let Some((_, s, _)) = data.screens.first() {
|
||||
show_screens.arc_set(s.name.clone());
|
||||
}
|
||||
for (meta, mut state, backend) in data.screens {
|
||||
if show_screens.arc_get(state.name.as_ref()) {
|
||||
state.show_hide = true;
|
||||
}
|
||||
overlays.insert(
|
||||
state.id.0,
|
||||
OverlayData::<T> {
|
||||
state,
|
||||
..OverlayData::from_backend(backend)
|
||||
},
|
||||
);
|
||||
app.screens.push(meta);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if show_screens.is_empty() {
|
||||
if let Some((_, s, _)) = data.screens.first() {
|
||||
show_screens.arc_set(s.name.clone());
|
||||
maybe_keymap = keymap;
|
||||
}
|
||||
}
|
||||
|
||||
for (meta, mut state, backend) in data.screens {
|
||||
if show_screens.arc_get(state.name.as_ref()) {
|
||||
state.show_hide = true;
|
||||
}
|
||||
overlays.insert(
|
||||
state.id.0,
|
||||
OverlayData::<T> {
|
||||
state,
|
||||
backend,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
app.screens.push(meta);
|
||||
Err(e) => log::error!("Unable to initialize screens: {e:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,147 +89,12 @@ where
|
||||
watch.state.want_visible = true;
|
||||
overlays.insert(watch.state.id.0, watch);
|
||||
|
||||
let mut keyboard = create_keyboard(app, keymap)?;
|
||||
let mut keyboard = create_keyboard(app, maybe_keymap)?;
|
||||
keyboard.state.show_hide = show_screens.arc_get(KEYBOARD_NAME);
|
||||
keyboard.state.want_visible = false;
|
||||
overlays.insert(keyboard.state.id.0, keyboard);
|
||||
|
||||
Ok(Self { overlays, wl })
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "wayland"))]
|
||||
pub fn update(&mut self, _app: &mut AppState) -> anyhow::Result<Vec<OverlayData<T>>> {
|
||||
Ok(vec![])
|
||||
}
|
||||
#[cfg(feature = "wayland")]
|
||||
#[allow(clippy::too_many_lines, clippy::cognitive_complexity)]
|
||||
#[allow(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)]
|
||||
pub fn update(&mut self, app: &mut AppState) -> anyhow::Result<Vec<OverlayData<T>>> {
|
||||
use crate::overlays::screen::{
|
||||
create_screen_interaction, create_screen_renderer_wl, load_pw_token_config,
|
||||
};
|
||||
use glam::vec2;
|
||||
use wlx_capture::wayland::OutputChangeEvent;
|
||||
|
||||
let mut removed_overlays = vec![];
|
||||
let Some(wl) = self.wl.as_mut() else {
|
||||
return Ok(removed_overlays);
|
||||
};
|
||||
|
||||
wl.dispatch_pending();
|
||||
|
||||
let mut create_ran = false;
|
||||
let mut extent_dirty = false;
|
||||
let mut watch_dirty = false;
|
||||
|
||||
let mut maybe_token_store = None;
|
||||
|
||||
for ev in wl.iter_events().collect::<Vec<_>>() {
|
||||
match ev {
|
||||
OutputChangeEvent::Create(_) => {
|
||||
if create_ran {
|
||||
continue;
|
||||
}
|
||||
let data = crate::overlays::screen::create_screens_wayland(wl, app);
|
||||
create_ran = true;
|
||||
for (meta, state, backend) in data.screens {
|
||||
self.overlays.insert(
|
||||
state.id.0,
|
||||
OverlayData::<T> {
|
||||
state,
|
||||
backend,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
app.screens.push(meta);
|
||||
watch_dirty = true;
|
||||
}
|
||||
}
|
||||
OutputChangeEvent::Destroy(id) => {
|
||||
let Some(idx) = app.screens.iter().position(|s| s.native_handle == id) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let meta = &app.screens[idx];
|
||||
let removed = self.overlays.remove(meta.id.0).unwrap();
|
||||
removed_overlays.push(removed);
|
||||
log::info!("{}: Destroyed", meta.name);
|
||||
app.screens.remove(idx);
|
||||
watch_dirty = true;
|
||||
extent_dirty = true;
|
||||
}
|
||||
OutputChangeEvent::Logical(id) => {
|
||||
let Some(meta) = app.screens.iter().find(|s| s.native_handle == id) else {
|
||||
continue;
|
||||
};
|
||||
let output = wl.outputs.get(id).unwrap();
|
||||
let Some(overlay) = self.overlays.get_mut(meta.id.0) else {
|
||||
continue;
|
||||
};
|
||||
let logical_pos =
|
||||
vec2(output.logical_pos.0 as f32, output.logical_pos.1 as f32);
|
||||
let logical_size =
|
||||
vec2(output.logical_size.0 as f32, output.logical_size.1 as f32);
|
||||
let transform = output.transform.into();
|
||||
overlay
|
||||
.backend
|
||||
.set_interaction(Box::new(create_screen_interaction(
|
||||
logical_pos,
|
||||
logical_size,
|
||||
transform,
|
||||
)));
|
||||
extent_dirty = true;
|
||||
}
|
||||
OutputChangeEvent::Physical(id) => {
|
||||
let Some(meta) = app.screens.iter().find(|s| s.native_handle == id) else {
|
||||
continue;
|
||||
};
|
||||
let output = wl.outputs.get(id).unwrap();
|
||||
let Some(overlay) = self.overlays.get_mut(meta.id.0) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let has_wlr_dmabuf = wl.maybe_wlr_dmabuf_mgr.is_some();
|
||||
let has_wlr_screencopy = wl.maybe_wlr_screencopy_mgr.is_some();
|
||||
|
||||
let pw_token_store = maybe_token_store.get_or_insert_with(|| {
|
||||
load_pw_token_config().unwrap_or_else(|e| {
|
||||
log::warn!("Failed to load PipeWire token config: {:?}", e);
|
||||
Default::default()
|
||||
})
|
||||
});
|
||||
|
||||
if let Some(renderer) = create_screen_renderer_wl(
|
||||
output,
|
||||
has_wlr_dmabuf,
|
||||
has_wlr_screencopy,
|
||||
pw_token_store,
|
||||
&app,
|
||||
) {
|
||||
overlay.backend.set_renderer(Box::new(renderer));
|
||||
}
|
||||
extent_dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if extent_dirty && !create_ran {
|
||||
let extent = wl.get_desktop_extent();
|
||||
let origin = wl.get_desktop_origin();
|
||||
app.hid_provider
|
||||
.inner
|
||||
.set_desktop_extent(vec2(extent.0 as f32, extent.1 as f32));
|
||||
app.hid_provider
|
||||
.inner
|
||||
.set_desktop_origin(vec2(origin.0 as f32, origin.1 as f32));
|
||||
}
|
||||
|
||||
if watch_dirty {
|
||||
let _watch = self.mut_by_name(WATCH_NAME).unwrap(); // want panic
|
||||
todo!();
|
||||
}
|
||||
|
||||
Ok(removed_overlays)
|
||||
Ok(Self { overlays })
|
||||
}
|
||||
|
||||
pub fn mut_by_selector(&mut self, selector: &OverlaySelector) -> Option<&mut OverlayData<T>> {
|
||||
|
||||
@@ -256,24 +256,6 @@ pub struct Haptics {
|
||||
pub frequency: f32,
|
||||
}
|
||||
|
||||
pub trait InteractionHandler {
|
||||
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> Option<Haptics>;
|
||||
fn on_left(&mut self, app: &mut AppState, pointer: usize);
|
||||
fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool);
|
||||
fn on_scroll(&mut self, app: &mut AppState, hit: &PointerHit, delta_y: f32, delta_x: f32);
|
||||
}
|
||||
|
||||
pub struct DummyInteractionHandler;
|
||||
|
||||
impl InteractionHandler for DummyInteractionHandler {
|
||||
fn on_left(&mut self, _app: &mut AppState, _pointer: usize) {}
|
||||
fn on_hover(&mut self, _app: &mut AppState, _hit: &PointerHit) -> Option<Haptics> {
|
||||
None
|
||||
}
|
||||
fn on_pointer(&mut self, _app: &mut AppState, _hit: &PointerHit, _pressed: bool) {}
|
||||
fn on_scroll(&mut self, _app: &mut AppState, _hit: &PointerHit, _delta_y: f32, _delta_x: f32) {}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
struct RayHit {
|
||||
overlay: OverlayID,
|
||||
@@ -493,12 +475,16 @@ impl Pointer {
|
||||
hits.sort_by(|a, b| a.dist.total_cmp(&b.dist));
|
||||
|
||||
for hit in &hits {
|
||||
let overlay = overlays.get_by_id(hit.overlay).unwrap(); // safe because we just got the id from the overlay
|
||||
let overlay = overlays.mut_by_id(hit.overlay).unwrap(); // safe because we just got the id from the overlay
|
||||
|
||||
let uv = overlay
|
||||
.state
|
||||
.interaction_transform
|
||||
.transform_point2(hit.local_pos);
|
||||
let Some(uv) = overlay
|
||||
.backend
|
||||
.as_mut()
|
||||
.get_interaction_transform()
|
||||
.map(|a| a.transform_point2(hit.local_pos))
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0 {
|
||||
continue;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::f32::consts::PI;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
use ash::vk::SubmitInfo;
|
||||
use glam::{Affine3A, Vec3, Vec3A, Vec4};
|
||||
@@ -8,6 +8,7 @@ use idmap::IdMap;
|
||||
use ovr_overlay::overlay::OverlayManager;
|
||||
use ovr_overlay::sys::ETrackingUniverseOrigin;
|
||||
use vulkano::{
|
||||
VulkanObject,
|
||||
command_buffer::{
|
||||
CommandBufferBeginInfo, CommandBufferLevel, CommandBufferUsage, RecordingCommandBuffer,
|
||||
},
|
||||
@@ -15,16 +16,15 @@ use vulkano::{
|
||||
image::view::ImageView,
|
||||
image::{Image, ImageLayout},
|
||||
sync::{
|
||||
fence::{Fence, FenceCreateInfo},
|
||||
AccessFlags, DependencyInfo, ImageMemoryBarrier, PipelineStages,
|
||||
fence::{Fence, FenceCreateInfo},
|
||||
},
|
||||
VulkanObject,
|
||||
};
|
||||
use wgui::gfx::WGfx;
|
||||
|
||||
use crate::backend::input::{Haptics, PointerHit};
|
||||
use crate::backend::overlay::{
|
||||
FrameMeta, OverlayData, OverlayRenderer, OverlayState, ShouldRender, SplitOverlayBackend,
|
||||
Z_ORDER_LINES,
|
||||
FrameMeta, OverlayBackend, OverlayData, OverlayState, ShouldRender, Z_ORDER_LINES,
|
||||
};
|
||||
use crate::graphics::CommandBuffers;
|
||||
use crate::state::AppState;
|
||||
@@ -81,12 +81,6 @@ impl LinePool {
|
||||
show_hide: true,
|
||||
..Default::default()
|
||||
},
|
||||
backend: Box::new(SplitOverlayBackend {
|
||||
renderer: Box::new(StaticRenderer {
|
||||
view: self.view.clone(),
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
data: OpenVrOverlayData {
|
||||
width: 0.002,
|
||||
override_width: true,
|
||||
@@ -94,7 +88,9 @@ impl LinePool {
|
||||
image_dirty: true,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
..OverlayData::from_backend(Box::new(LineBackend {
|
||||
view: self.view.clone(),
|
||||
}))
|
||||
};
|
||||
data.state.z_order = Z_ORDER_LINES;
|
||||
data.state.dirty = true;
|
||||
@@ -177,29 +173,29 @@ impl LinePool {
|
||||
}
|
||||
}
|
||||
|
||||
struct StaticRenderer {
|
||||
struct LineBackend {
|
||||
view: Arc<ImageView>,
|
||||
}
|
||||
|
||||
impl OverlayRenderer for StaticRenderer {
|
||||
fn init(&mut self, _app: &mut AppState) -> anyhow::Result<()> {
|
||||
impl OverlayBackend for LineBackend {
|
||||
fn init(&mut self, _: &mut AppState) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn pause(&mut self, _app: &mut AppState) -> anyhow::Result<()> {
|
||||
fn pause(&mut self, _: &mut AppState) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn resume(&mut self, _app: &mut AppState) -> anyhow::Result<()> {
|
||||
fn resume(&mut self, _: &mut AppState) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn should_render(&mut self, _app: &mut AppState) -> anyhow::Result<ShouldRender> {
|
||||
fn should_render(&mut self, _: &mut AppState) -> anyhow::Result<ShouldRender> {
|
||||
Ok(ShouldRender::Unable)
|
||||
}
|
||||
fn render(
|
||||
&mut self,
|
||||
_app: &mut AppState,
|
||||
_tgt: Arc<ImageView>,
|
||||
_buf: &mut CommandBuffers,
|
||||
_alpha: f32,
|
||||
_: &mut AppState,
|
||||
_: Arc<ImageView>,
|
||||
_: &mut CommandBuffers,
|
||||
_: f32,
|
||||
) -> anyhow::Result<bool> {
|
||||
Ok(false)
|
||||
}
|
||||
@@ -209,6 +205,16 @@ impl OverlayRenderer for StaticRenderer {
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
fn on_hover(&mut self, _: &mut AppState, _: &PointerHit) -> Option<Haptics> {
|
||||
None
|
||||
}
|
||||
fn on_left(&mut self, _: &mut AppState, _: usize) {}
|
||||
fn on_pointer(&mut self, _: &mut AppState, _: &PointerHit, _: bool) {}
|
||||
fn on_scroll(&mut self, _: &mut AppState, _: &PointerHit, _: f32, _: f32) {}
|
||||
fn get_interaction_transform(&mut self) -> Option<glam::Affine2> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn transition_layout(
|
||||
|
||||
@@ -204,11 +204,6 @@ pub fn openvr_run(
|
||||
|
||||
state.tasks.retrieve_due(&mut due_tasks);
|
||||
|
||||
let mut removed_overlays = overlays.update(&mut state)?;
|
||||
for o in &mut removed_overlays {
|
||||
o.destroy(&mut overlay_mgr);
|
||||
}
|
||||
|
||||
while let Some(task) = due_tasks.pop_front() {
|
||||
match task {
|
||||
TaskType::Overlay(sel, f) => {
|
||||
@@ -230,8 +225,7 @@ pub fn openvr_run(
|
||||
|
||||
overlays.add(OverlayData {
|
||||
state,
|
||||
backend,
|
||||
..Default::default()
|
||||
..OverlayData::from_backend(backend)
|
||||
});
|
||||
}
|
||||
TaskType::DropOverlay(sel) => {
|
||||
|
||||
@@ -486,11 +486,6 @@ pub fn openxr_run(
|
||||
)?;
|
||||
// End layer submit
|
||||
|
||||
let removed_overlays = overlays.update(&mut app)?;
|
||||
for o in removed_overlays {
|
||||
delete_queue.push((o, cur_frame + 5));
|
||||
}
|
||||
|
||||
notifications.submit_pending(&mut app);
|
||||
|
||||
app.tasks.retrieve_due(&mut due_tasks);
|
||||
@@ -515,8 +510,7 @@ pub fn openxr_run(
|
||||
|
||||
overlays.add(OverlayData {
|
||||
state: overlay_state,
|
||||
backend: overlay_backend,
|
||||
..Default::default()
|
||||
..OverlayData::from_backend(overlay_backend)
|
||||
});
|
||||
}
|
||||
TaskType::DropOverlay(sel) => {
|
||||
|
||||
@@ -6,7 +6,6 @@ use std::{
|
||||
},
|
||||
};
|
||||
|
||||
use anyhow::Ok;
|
||||
use glam::{Affine2, Affine3A, Mat3A, Quat, Vec2, Vec3, Vec3A};
|
||||
use serde::Deserialize;
|
||||
use vulkano::{format::Format, image::view::ImageView};
|
||||
@@ -17,16 +16,11 @@ use crate::{
|
||||
|
||||
use super::{
|
||||
common::snap_upright,
|
||||
input::{DummyInteractionHandler, Haptics, InteractionHandler, PointerHit},
|
||||
input::{Haptics, PointerHit},
|
||||
};
|
||||
|
||||
static OVERLAY_AUTO_INCREMENT: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
pub trait OverlayBackend: OverlayRenderer + InteractionHandler {
|
||||
fn set_renderer(&mut self, renderer: Box<dyn OverlayRenderer>);
|
||||
fn set_interaction(&mut self, interaction: Box<dyn InteractionHandler>);
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Default)]
|
||||
pub struct OverlayID(pub usize);
|
||||
|
||||
@@ -56,7 +50,6 @@ pub struct OverlayState {
|
||||
pub saved_transform: Option<Affine3A>,
|
||||
pub positioning: Positioning,
|
||||
pub curvature: Option<f32>,
|
||||
pub interaction_transform: Affine2,
|
||||
pub birthframe: usize,
|
||||
}
|
||||
|
||||
@@ -81,32 +74,28 @@ impl Default for OverlayState {
|
||||
spawn_rotation: Quat::IDENTITY,
|
||||
saved_transform: None,
|
||||
transform: Affine3A::IDENTITY,
|
||||
interaction_transform: Affine2::IDENTITY,
|
||||
birthframe: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OverlayData<T>
|
||||
where
|
||||
T: Default,
|
||||
{
|
||||
pub struct OverlayData<T> {
|
||||
pub state: OverlayState,
|
||||
pub backend: Box<dyn OverlayBackend>,
|
||||
pub primary_pointer: Option<usize>,
|
||||
pub data: T,
|
||||
}
|
||||
|
||||
impl<T> Default for OverlayData<T>
|
||||
impl<T> OverlayData<T>
|
||||
where
|
||||
T: Default,
|
||||
{
|
||||
fn default() -> Self {
|
||||
pub fn from_backend(backend: Box<dyn OverlayBackend>) -> Self {
|
||||
Self {
|
||||
state: OverlayState::default(),
|
||||
backend: Box::<SplitOverlayBackend>::default(),
|
||||
backend,
|
||||
primary_pointer: None,
|
||||
data: Default::default(),
|
||||
data: T::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -166,7 +155,7 @@ impl OverlayState {
|
||||
app.input_state.pointers[hand].pose
|
||||
}
|
||||
Positioning::Anchored => app.anchor,
|
||||
Positioning::Static => return,
|
||||
Positioning::FollowOverlay { .. } | Positioning::Static => return,
|
||||
};
|
||||
|
||||
if hard_reset {
|
||||
@@ -191,7 +180,7 @@ impl OverlayState {
|
||||
app.input_state.pointers[hand].pose
|
||||
}
|
||||
Positioning::Anchored => snap_upright(app.anchor, Vec3A::Y),
|
||||
Positioning::Static => return false,
|
||||
Positioning::FollowOverlay { .. } | Positioning::Static => return false,
|
||||
};
|
||||
|
||||
self.saved_transform = Some(parent_transform.inverse() * self.transform);
|
||||
@@ -307,7 +296,7 @@ pub enum ShouldRender {
|
||||
Unable,
|
||||
}
|
||||
|
||||
pub trait OverlayRenderer {
|
||||
pub trait OverlayBackend {
|
||||
/// Called once, before the first frame is rendered
|
||||
fn init(&mut self, app: &mut AppState) -> anyhow::Result<()>;
|
||||
fn pause(&mut self, app: &mut AppState) -> anyhow::Result<()>;
|
||||
@@ -330,37 +319,13 @@ pub trait OverlayRenderer {
|
||||
///
|
||||
/// Must be true if should_render was also true on the same frame.
|
||||
fn frame_meta(&mut self) -> Option<FrameMeta>;
|
||||
}
|
||||
|
||||
pub struct FallbackRenderer;
|
||||
|
||||
impl OverlayRenderer for FallbackRenderer {
|
||||
fn init(&mut self, _app: &mut AppState) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn pause(&mut self, _app: &mut AppState) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn resume(&mut self, _app: &mut AppState) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn should_render(&mut self, _app: &mut AppState) -> anyhow::Result<ShouldRender> {
|
||||
Ok(ShouldRender::Unable)
|
||||
}
|
||||
fn render(
|
||||
&mut self,
|
||||
_app: &mut AppState,
|
||||
_tgt: Arc<ImageView>,
|
||||
_buf: &mut CommandBuffers,
|
||||
_alpha: f32,
|
||||
) -> anyhow::Result<bool> {
|
||||
Ok(false)
|
||||
}
|
||||
fn frame_meta(&mut self) -> Option<FrameMeta> {
|
||||
None
|
||||
}
|
||||
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> Option<Haptics>;
|
||||
fn on_left(&mut self, app: &mut AppState, pointer: usize);
|
||||
fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool);
|
||||
fn on_scroll(&mut self, app: &mut AppState, hit: &PointerHit, delta_y: f32, delta_x: f32);
|
||||
fn get_interaction_transform(&mut self) -> Option<Affine2>;
|
||||
}
|
||||
// Boilerplate and dummies
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub enum Positioning {
|
||||
@@ -377,74 +342,12 @@ pub enum Positioning {
|
||||
FollowHand { hand: usize, lerp: f32 },
|
||||
/// Normally follows hand, but paused due to interaction
|
||||
FollowHandPaused { hand: usize, lerp: f32 },
|
||||
/// Follow another overlay
|
||||
FollowOverlay { id: usize },
|
||||
/// Stays in place, no recentering
|
||||
Static,
|
||||
}
|
||||
|
||||
pub struct SplitOverlayBackend {
|
||||
pub renderer: Box<dyn OverlayRenderer>,
|
||||
pub interaction: Box<dyn InteractionHandler>,
|
||||
}
|
||||
|
||||
impl Default for SplitOverlayBackend {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
renderer: Box::new(FallbackRenderer),
|
||||
interaction: Box::new(DummyInteractionHandler),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl OverlayBackend for SplitOverlayBackend {
|
||||
fn set_renderer(&mut self, renderer: Box<dyn OverlayRenderer>) {
|
||||
self.renderer = renderer;
|
||||
}
|
||||
fn set_interaction(&mut self, interaction: Box<dyn InteractionHandler>) {
|
||||
self.interaction = interaction;
|
||||
}
|
||||
}
|
||||
impl OverlayRenderer for SplitOverlayBackend {
|
||||
fn init(&mut self, app: &mut AppState) -> anyhow::Result<()> {
|
||||
self.renderer.init(app)
|
||||
}
|
||||
fn pause(&mut self, app: &mut AppState) -> anyhow::Result<()> {
|
||||
self.renderer.pause(app)
|
||||
}
|
||||
fn resume(&mut self, app: &mut AppState) -> anyhow::Result<()> {
|
||||
self.renderer.resume(app)
|
||||
}
|
||||
fn should_render(&mut self, app: &mut AppState) -> anyhow::Result<ShouldRender> {
|
||||
self.renderer.should_render(app)
|
||||
}
|
||||
fn render(
|
||||
&mut self,
|
||||
app: &mut AppState,
|
||||
tgt: Arc<ImageView>,
|
||||
buf: &mut CommandBuffers,
|
||||
alpha: f32,
|
||||
) -> anyhow::Result<bool> {
|
||||
self.renderer.render(app, tgt, buf, alpha)
|
||||
}
|
||||
fn frame_meta(&mut self) -> Option<FrameMeta> {
|
||||
self.renderer.frame_meta()
|
||||
}
|
||||
}
|
||||
|
||||
impl InteractionHandler for SplitOverlayBackend {
|
||||
fn on_left(&mut self, app: &mut AppState, pointer: usize) {
|
||||
self.interaction.on_left(app, pointer);
|
||||
}
|
||||
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> Option<Haptics> {
|
||||
self.interaction.on_hover(app, hit)
|
||||
}
|
||||
fn on_scroll(&mut self, app: &mut AppState, hit: &PointerHit, delta_y: f32, delta_x: f32) {
|
||||
self.interaction.on_scroll(app, hit, delta_y, delta_x);
|
||||
}
|
||||
fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool) {
|
||||
self.interaction.on_pointer(app, hit, pressed);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ui_transform(extent: [u32; 2]) -> Affine2 {
|
||||
let aspect = extent[0] as f32 / extent[1] as f32;
|
||||
let scale = if aspect < 1.0 {
|
||||
|
||||
Reference in New Issue
Block a user