sbs 3d support
This commit is contained in:
@@ -8,6 +8,7 @@ use std::{
|
||||
|
||||
use glam::vec2;
|
||||
use slotmap::Key;
|
||||
use smallvec::smallvec;
|
||||
use wgui::{
|
||||
components::{button::ComponentButton, checkbox::ComponentCheckbox, slider::ComponentSlider},
|
||||
event::{CallbackDataCommon, EventAlterables, EventCallback},
|
||||
@@ -16,25 +17,35 @@ use wgui::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
attrib_value,
|
||||
backend::{
|
||||
input::HoverResult,
|
||||
task::{OverlayTask, TaskContainer, TaskType},
|
||||
},
|
||||
gui::panel::{GuiPanel, NewGuiPanelParams, OnCustomAttribFunc, button::BUTTON_EVENTS},
|
||||
gui::panel::{button::BUTTON_EVENTS, GuiPanel, NewGuiPanelParams, OnCustomAttribFunc},
|
||||
overlays::edit::{
|
||||
lock::InteractLockHandler, pos::PositioningHandler, tab::ButtonPaneTabSwitcher,
|
||||
lock::InteractLockHandler,
|
||||
pos::{new_pos_tab_handler, PosTabState},
|
||||
sprite_tab::SpriteTabHandler,
|
||||
stereo::new_stereo_tab_handler,
|
||||
tab::ButtonPaneTabSwitcher,
|
||||
},
|
||||
state::AppState,
|
||||
subsystem::hid::WheelDelta,
|
||||
windowing::{
|
||||
OverlayID, OverlaySelector,
|
||||
backend::{DummyBackend, OverlayBackend, OverlayEventData, RenderResources, ShouldRender},
|
||||
backend::{
|
||||
BackendAttrib, BackendAttribValue, DummyBackend, OverlayBackend, OverlayEventData,
|
||||
RenderResources, ShouldRender, StereoMode,
|
||||
},
|
||||
window::OverlayWindowConfig,
|
||||
OverlayID, OverlaySelector,
|
||||
},
|
||||
};
|
||||
|
||||
mod lock;
|
||||
mod pos;
|
||||
mod sprite_tab;
|
||||
mod stereo;
|
||||
pub mod tab;
|
||||
|
||||
pub(super) struct LongPressButtonState {
|
||||
@@ -54,7 +65,8 @@ struct EditModeState {
|
||||
delete: LongPressButtonState,
|
||||
tabs: ButtonPaneTabSwitcher,
|
||||
lock: InteractLockHandler,
|
||||
pos: PositioningHandler,
|
||||
pos: SpriteTabHandler<PosTabState>,
|
||||
stereo: SpriteTabHandler<StereoMode>,
|
||||
}
|
||||
|
||||
type EditModeWrapPanel = GuiPanel<EditModeState>;
|
||||
@@ -77,7 +89,6 @@ impl EditWrapperManager {
|
||||
}
|
||||
|
||||
log::debug!("EditMode wrap on {}", owc.name);
|
||||
let inner = mem::replace(&mut owc.backend, Box::new(DummyBackend {}));
|
||||
let mut panel = self.panel_pool.pop();
|
||||
if panel.is_none() {
|
||||
panel = Some(make_edit_panel(app)?);
|
||||
@@ -85,6 +96,8 @@ impl EditWrapperManager {
|
||||
let mut panel = panel.unwrap();
|
||||
reset_panel(&mut panel, id, owc)?;
|
||||
|
||||
let inner = mem::replace(&mut owc.backend, Box::new(DummyBackend {}));
|
||||
|
||||
owc.backend = Box::new(EditModeBackendWrapper {
|
||||
inner: ManuallyDrop::new(inner),
|
||||
panel: ManuallyDrop::new(panel),
|
||||
@@ -178,7 +191,16 @@ impl OverlayBackend for EditModeBackendWrapper {
|
||||
rdr: &mut RenderResources,
|
||||
) -> anyhow::Result<()> {
|
||||
self.inner.render(app, rdr)?;
|
||||
self.panel.render(app, rdr)
|
||||
|
||||
self.panel.render(app, rdr)?;
|
||||
// `GuiPanel` is not stereo-aware, so just render the same pass twice
|
||||
if rdr.cmd_bufs.len() > 1 {
|
||||
rdr.cmd_bufs.reverse();
|
||||
self.panel.render(app, rdr)?;
|
||||
rdr.cmd_bufs.reverse();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
fn frame_meta(&mut self) -> Option<crate::windowing::backend::FrameMeta> {
|
||||
self.inner.frame_meta()
|
||||
@@ -218,6 +240,12 @@ impl OverlayBackend for EditModeBackendWrapper {
|
||||
fn get_interaction_transform(&mut self) -> Option<glam::Affine2> {
|
||||
self.inner.get_interaction_transform()
|
||||
}
|
||||
fn get_attrib(&self, attrib: BackendAttrib) -> Option<BackendAttribValue> {
|
||||
self.inner.get_attrib(attrib)
|
||||
}
|
||||
fn set_attrib(&mut self, app: &mut AppState, value: BackendAttribValue) -> bool {
|
||||
self.inner.set_attrib(app, value)
|
||||
}
|
||||
}
|
||||
|
||||
fn make_edit_panel(app: &mut AppState) -> anyhow::Result<EditModeWrapPanel> {
|
||||
@@ -229,7 +257,8 @@ fn make_edit_panel(app: &mut AppState) -> anyhow::Result<EditModeWrapPanel> {
|
||||
},
|
||||
tabs: ButtonPaneTabSwitcher::default(),
|
||||
lock: InteractLockHandler::default(),
|
||||
pos: PositioningHandler::default(),
|
||||
pos: SpriteTabHandler::default(),
|
||||
stereo: SpriteTabHandler::default(),
|
||||
};
|
||||
|
||||
let on_custom_attrib: OnCustomAttribFunc = Box::new(move |layout, attribs, _app| {
|
||||
@@ -270,10 +299,20 @@ fn make_edit_panel(app: &mut AppState) -> anyhow::Result<EditModeWrapPanel> {
|
||||
})
|
||||
}
|
||||
"::EditModeSetPos" => {
|
||||
let pos_key = args.next().unwrap().to_owned();
|
||||
let key = args.next().unwrap().to_owned();
|
||||
Box::new(move |common, _data, app, state| {
|
||||
let sel = OverlaySelector::Id(*state.id.borrow());
|
||||
let task = state.pos.pos_button_clicked(common, &pos_key);
|
||||
let task = state.pos.button_clicked(common, &key);
|
||||
app.tasks
|
||||
.enqueue(TaskType::Overlay(OverlayTask::Modify(sel, task)));
|
||||
Ok(EventResult::Consumed)
|
||||
})
|
||||
}
|
||||
"::EditModeSetStereo" => {
|
||||
let key = args.next().unwrap().to_owned();
|
||||
Box::new(move |common, _data, app, state| {
|
||||
let sel = OverlaySelector::Id(*state.id.borrow());
|
||||
let task = state.stereo.button_clicked(common, &key);
|
||||
app.tasks
|
||||
.enqueue(TaskType::Overlay(OverlayTask::Modify(sel, task)));
|
||||
Ok(EventResult::Consumed)
|
||||
@@ -315,9 +354,11 @@ fn make_edit_panel(app: &mut AppState) -> anyhow::Result<EditModeWrapPanel> {
|
||||
},
|
||||
)?;
|
||||
|
||||
panel.state.pos = PositioningHandler::new(&mut panel)?;
|
||||
panel.state.pos = new_pos_tab_handler(&mut panel)?;
|
||||
panel.state.stereo = new_stereo_tab_handler(&mut panel)?;
|
||||
panel.state.lock = InteractLockHandler::new(&mut panel)?;
|
||||
panel.state.tabs = ButtonPaneTabSwitcher::new(&mut panel, &["none", "pos", "alpha", "curve"])?;
|
||||
panel.state.tabs =
|
||||
ButtonPaneTabSwitcher::new(&mut panel, &["none", "pos", "alpha", "curve", "stereo"])?;
|
||||
|
||||
set_up_checkbox(&mut panel, "additive_box", cb_assign_additive)?;
|
||||
set_up_slider(&mut panel, "lerp_slider", cb_assign_lerp)?;
|
||||
@@ -366,10 +407,29 @@ fn reset_panel(
|
||||
.fetch_component_as::<ComponentCheckbox>("additive_box")?;
|
||||
c.set_checked(&mut common, state.additive);
|
||||
|
||||
panel.state.pos.reset(&mut common, state.positioning);
|
||||
panel
|
||||
.state
|
||||
.pos
|
||||
.reset(&mut common, &state.positioning.into());
|
||||
panel.state.lock.reset(&mut common, state.interactable);
|
||||
panel.state.tabs.reset(&mut common);
|
||||
|
||||
if let Some(stereo) = attrib_value!(
|
||||
owc.backend.get_attrib(BackendAttrib::Stereo),
|
||||
BackendAttribValue::Stereo
|
||||
) {
|
||||
panel
|
||||
.state
|
||||
.tabs
|
||||
.set_tab_visible(&mut common, "stereo", true);
|
||||
panel.state.stereo.reset(&mut common, &stereo);
|
||||
} else {
|
||||
panel
|
||||
.state
|
||||
.tabs
|
||||
.set_tab_visible(&mut common, "stereo", false);
|
||||
}
|
||||
|
||||
panel.layout.process_alterables(alterables)?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1,174 +1,116 @@
|
||||
use std::{collections::HashMap, rc::Rc};
|
||||
|
||||
use wgui::{
|
||||
components::button::ComponentButton,
|
||||
event::{CallbackDataCommon, StyleSetRequest},
|
||||
layout::WidgetID,
|
||||
parser::Fetchable,
|
||||
renderer_vk::text::custom_glyph::CustomGlyphData,
|
||||
taffy,
|
||||
widget::sprite::WidgetSprite,
|
||||
};
|
||||
use wgui::{event::StyleSetRequest, parser::Fetchable, taffy};
|
||||
use wlx_common::{common::LeftRight, windowing::Positioning};
|
||||
|
||||
use crate::{
|
||||
backend::task::ModifyOverlayTask, overlays::edit::EditModeWrapPanel, windowing::window,
|
||||
overlays::edit::{
|
||||
sprite_tab::{SpriteTabHandler, SpriteTabKey},
|
||||
EditModeWrapPanel,
|
||||
},
|
||||
windowing::window,
|
||||
};
|
||||
|
||||
static POS_NAMES: [&str; 6] = ["static", "anchored", "floating", "hmd", "hand_l", "hand_r"];
|
||||
|
||||
struct PosButtonState {
|
||||
name: &'static str,
|
||||
sprite: CustomGlyphData,
|
||||
component: Rc<ComponentButton>,
|
||||
positioning: Positioning,
|
||||
has_interpolation: bool,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(super) struct PositioningHandler {
|
||||
top_sprite_id: WidgetID,
|
||||
interpolation_id: WidgetID,
|
||||
buttons: HashMap<&'static str, Rc<PosButtonState>>,
|
||||
active_button: Option<Rc<PosButtonState>>,
|
||||
pub struct PosTabState {
|
||||
pos: Positioning,
|
||||
has_lerp: bool,
|
||||
}
|
||||
|
||||
impl PositioningHandler {
|
||||
pub fn new(panel: &mut EditModeWrapPanel) -> anyhow::Result<Self> {
|
||||
let mut buttons = HashMap::new();
|
||||
impl From<Positioning> for PosTabState {
|
||||
fn from(value: Positioning) -> Self {
|
||||
Self {
|
||||
pos: value,
|
||||
has_lerp: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for name in &POS_NAMES {
|
||||
let button_id = format!("pos_{name}");
|
||||
let component = panel.parser_state.fetch_component_as(&button_id)?;
|
||||
pub fn new_pos_tab_handler(
|
||||
panel: &mut EditModeWrapPanel,
|
||||
) -> anyhow::Result<SpriteTabHandler<PosTabState>> {
|
||||
let interpolation_id = panel.parser_state.get_widget_id("pos_interpolation")?;
|
||||
|
||||
let sprite_id = format!("{button_id}_sprite");
|
||||
let id = panel.parser_state.get_widget_id(&sprite_id)?;
|
||||
let sprite_w = panel
|
||||
.layout
|
||||
.state
|
||||
.widgets
|
||||
.get_as::<WidgetSprite>(id)
|
||||
.ok_or_else(|| {
|
||||
anyhow::anyhow!("Element with id=\"{sprite_id}\" must be a <sprite>")
|
||||
})?;
|
||||
SpriteTabHandler::new(
|
||||
panel,
|
||||
"pos",
|
||||
&POS_NAMES,
|
||||
Box::new(|_common, state| {
|
||||
let positioning = state.pos;
|
||||
Box::new(move |app, owc| {
|
||||
let state = owc.active_state.as_mut().unwrap(); //want panic
|
||||
state.positioning = positioning;
|
||||
window::save_transform(state, app);
|
||||
})
|
||||
}),
|
||||
Some(Box::new(move |common, state| {
|
||||
let interpolation_disp = if state.has_lerp {
|
||||
taffy::Display::Flex
|
||||
} else {
|
||||
taffy::Display::None
|
||||
};
|
||||
|
||||
let sprite = sprite_w.params.glyph_data.clone().ok_or_else(|| {
|
||||
anyhow::anyhow!("Element with id=\"{sprite_id}\" must have a valid src!")
|
||||
})?;
|
||||
|
||||
let (positioning, has_interpolation) = key_to_pos(name);
|
||||
|
||||
buttons.insert(
|
||||
*name,
|
||||
Rc::new(PosButtonState {
|
||||
name,
|
||||
sprite,
|
||||
component,
|
||||
positioning,
|
||||
has_interpolation,
|
||||
}),
|
||||
common.alterables.set_style(
|
||||
interpolation_id,
|
||||
StyleSetRequest::Display(interpolation_disp),
|
||||
);
|
||||
}
|
||||
|
||||
let top_sprite_id = panel.parser_state.get_widget_id("top_pos_sprite")?;
|
||||
let interpolation_id = panel.parser_state.get_widget_id("pos_interpolation")?;
|
||||
Ok(Self {
|
||||
buttons,
|
||||
active_button: None,
|
||||
top_sprite_id,
|
||||
interpolation_id,
|
||||
})
|
||||
}
|
||||
|
||||
fn change_highlight(&mut self, common: &mut CallbackDataCommon, key: &str) {
|
||||
if let Some(old) = self.active_button.take() {
|
||||
old.component.set_sticky_state(common, false);
|
||||
}
|
||||
let new = self.buttons.get_mut(key).unwrap();
|
||||
new.component.set_sticky_state(common, true);
|
||||
self.active_button = Some(new.clone());
|
||||
|
||||
let interpolation_disp = if new.has_interpolation {
|
||||
taffy::Display::Flex
|
||||
} else {
|
||||
taffy::Display::None
|
||||
};
|
||||
|
||||
common.alterables.set_style(
|
||||
self.interpolation_id,
|
||||
StyleSetRequest::Display(interpolation_disp),
|
||||
);
|
||||
|
||||
// change top sprite
|
||||
if let Some(mut sprite) = common
|
||||
.state
|
||||
.widgets
|
||||
.get_as::<WidgetSprite>(self.top_sprite_id)
|
||||
{
|
||||
sprite.params.glyph_data = Some(new.sprite.clone());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pos_button_clicked(
|
||||
&mut self,
|
||||
common: &mut CallbackDataCommon,
|
||||
key: &str,
|
||||
) -> Box<ModifyOverlayTask> {
|
||||
self.change_highlight(common, key);
|
||||
|
||||
let (pos, _) = key_to_pos(key);
|
||||
Box::new(move |app, owc| {
|
||||
let state = owc.active_state.as_mut().unwrap(); //want panic
|
||||
state.positioning = pos;
|
||||
window::save_transform(state, app);
|
||||
})
|
||||
}
|
||||
|
||||
pub fn reset(&mut self, common: &mut CallbackDataCommon, pos: Positioning) {
|
||||
let key = pos_to_key(pos);
|
||||
self.change_highlight(common, key);
|
||||
}
|
||||
})),
|
||||
)
|
||||
}
|
||||
|
||||
fn key_to_pos(key: &str) -> (Positioning, bool) {
|
||||
match key {
|
||||
"static" => (Positioning::Static, false),
|
||||
"anchored" => (Positioning::Anchored, false),
|
||||
"floating" => (Positioning::Floating, false),
|
||||
"hmd" => (Positioning::FollowHead { lerp: 1.0 }, true),
|
||||
"hand_l" => (
|
||||
impl SpriteTabKey for PosTabState {
|
||||
fn to_tab_key(&self) -> &'static str {
|
||||
match self.pos {
|
||||
Positioning::Static => "static",
|
||||
Positioning::Anchored => "anchored",
|
||||
Positioning::Floating => "floating",
|
||||
Positioning::FollowHead { .. } => "hmd",
|
||||
Positioning::FollowHand {
|
||||
hand: LeftRight::Left,
|
||||
lerp: 1.0,
|
||||
},
|
||||
true,
|
||||
),
|
||||
"hand_r" => (
|
||||
..
|
||||
} => "hand_l",
|
||||
Positioning::FollowHand {
|
||||
hand: LeftRight::Right,
|
||||
lerp: 1.0,
|
||||
..
|
||||
} => "hand_r",
|
||||
}
|
||||
}
|
||||
|
||||
fn from_tab_key(key: &str) -> Self {
|
||||
match key {
|
||||
"static" => PosTabState {
|
||||
pos: Positioning::Static,
|
||||
has_lerp: false,
|
||||
},
|
||||
true,
|
||||
),
|
||||
_ => {
|
||||
panic!("cannot translate to positioning: {key}")
|
||||
"anchored" => PosTabState {
|
||||
pos: Positioning::Anchored,
|
||||
has_lerp: false,
|
||||
},
|
||||
"floating" => PosTabState {
|
||||
pos: Positioning::Floating,
|
||||
has_lerp: false,
|
||||
},
|
||||
"hmd" => PosTabState {
|
||||
pos: Positioning::FollowHead { lerp: 1.0 },
|
||||
has_lerp: true,
|
||||
},
|
||||
"hand_l" => PosTabState {
|
||||
pos: Positioning::FollowHand {
|
||||
hand: LeftRight::Left,
|
||||
lerp: 1.0,
|
||||
},
|
||||
has_lerp: true,
|
||||
},
|
||||
"hand_r" => PosTabState {
|
||||
pos: Positioning::FollowHand {
|
||||
hand: LeftRight::Right,
|
||||
lerp: 1.0,
|
||||
},
|
||||
has_lerp: true,
|
||||
},
|
||||
_ => {
|
||||
panic!("cannot translate to positioning: {key}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const fn pos_to_key(pos: Positioning) -> &'static str {
|
||||
match pos {
|
||||
Positioning::Static => "static",
|
||||
Positioning::Anchored => "anchored",
|
||||
Positioning::Floating => "floating",
|
||||
Positioning::FollowHead { .. } => "hmd",
|
||||
Positioning::FollowHand {
|
||||
hand: LeftRight::Left,
|
||||
..
|
||||
} => "hand_l",
|
||||
Positioning::FollowHand {
|
||||
hand: LeftRight::Right,
|
||||
..
|
||||
} => "hand_r",
|
||||
}
|
||||
}
|
||||
|
||||
129
wlx-overlay-s/src/overlays/edit/sprite_tab.rs
Normal file
129
wlx-overlay-s/src/overlays/edit/sprite_tab.rs
Normal file
@@ -0,0 +1,129 @@
|
||||
use std::{collections::HashMap, rc::Rc};
|
||||
|
||||
use wgui::{
|
||||
components::button::ComponentButton, event::CallbackDataCommon, layout::WidgetID,
|
||||
parser::Fetchable, renderer_vk::text::custom_glyph::CustomGlyphData,
|
||||
widget::sprite::WidgetSprite,
|
||||
};
|
||||
|
||||
use crate::{backend::task::ModifyOverlayTask, overlays::edit::EditModeWrapPanel};
|
||||
|
||||
pub trait SpriteTabKey {
|
||||
fn to_tab_key(&self) -> &'static str;
|
||||
fn from_tab_key(key: &str) -> Self;
|
||||
}
|
||||
|
||||
struct SpriteTabButtonState<S> {
|
||||
name: &'static str,
|
||||
sprite: CustomGlyphData,
|
||||
component: Rc<ComponentButton>,
|
||||
state: S,
|
||||
}
|
||||
|
||||
pub type SpriteTabHighlightChanged<S> = dyn Fn(&mut CallbackDataCommon, &S);
|
||||
pub type SpriteTabButtonClicked<S> = dyn Fn(&mut CallbackDataCommon, &S) -> Box<ModifyOverlayTask>;
|
||||
|
||||
#[derive(Default)]
|
||||
pub(super) struct SpriteTabHandler<S> {
|
||||
top_sprite_id: WidgetID,
|
||||
buttons: HashMap<&'static str, Rc<SpriteTabButtonState<S>>>,
|
||||
active_button: Option<Rc<SpriteTabButtonState<S>>>,
|
||||
on_highlight_changed: Option<Box<SpriteTabHighlightChanged<S>>>,
|
||||
on_button_clicked: Option<Box<SpriteTabButtonClicked<S>>>,
|
||||
}
|
||||
|
||||
impl<S> SpriteTabHandler<S>
|
||||
where
|
||||
S: SpriteTabKey,
|
||||
{
|
||||
pub fn new(
|
||||
panel: &mut EditModeWrapPanel,
|
||||
prefix: &str,
|
||||
names: &[&'static str],
|
||||
on_button_clicked: Box<SpriteTabButtonClicked<S>>,
|
||||
on_highlight_changed: Option<Box<SpriteTabHighlightChanged<S>>>,
|
||||
) -> anyhow::Result<Self> {
|
||||
let mut buttons = HashMap::new();
|
||||
|
||||
for name in names {
|
||||
let button_id = format!("{prefix}_{name}");
|
||||
let component = panel.parser_state.fetch_component_as(&button_id)?;
|
||||
|
||||
let sprite_id = format!("{button_id}_sprite");
|
||||
let id = panel.parser_state.get_widget_id(&sprite_id)?;
|
||||
let sprite_w = panel
|
||||
.layout
|
||||
.state
|
||||
.widgets
|
||||
.get_as::<WidgetSprite>(id)
|
||||
.ok_or_else(|| {
|
||||
anyhow::anyhow!("Element with id=\"{sprite_id}\" must be a <sprite>")
|
||||
})?;
|
||||
|
||||
let sprite = sprite_w.params.glyph_data.clone().ok_or_else(|| {
|
||||
anyhow::anyhow!("Element with id=\"{sprite_id}\" must have a valid src!")
|
||||
})?;
|
||||
|
||||
let state = S::from_tab_key(name);
|
||||
|
||||
buttons.insert(
|
||||
*name,
|
||||
Rc::new(SpriteTabButtonState {
|
||||
name,
|
||||
sprite,
|
||||
component,
|
||||
state,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
let top_sprite_id = panel
|
||||
.parser_state
|
||||
.get_widget_id(&format!("top_{prefix}_sprite"))?;
|
||||
Ok(Self {
|
||||
buttons,
|
||||
active_button: None,
|
||||
top_sprite_id,
|
||||
on_highlight_changed,
|
||||
on_button_clicked: Some(on_button_clicked),
|
||||
})
|
||||
}
|
||||
|
||||
fn change_highlight(&mut self, common: &mut CallbackDataCommon, key: &str) {
|
||||
if let Some(old) = self.active_button.take() {
|
||||
old.component.set_sticky_state(common, false);
|
||||
}
|
||||
let new = self.buttons.get_mut(key).unwrap();
|
||||
new.component.set_sticky_state(common, true);
|
||||
self.active_button = Some(new.clone());
|
||||
|
||||
if let Some(highlight_changed) = self.on_highlight_changed.as_ref() {
|
||||
highlight_changed(common, &new.state);
|
||||
}
|
||||
|
||||
// change top sprite
|
||||
if let Some(mut sprite) = common
|
||||
.state
|
||||
.widgets
|
||||
.get_as::<WidgetSprite>(self.top_sprite_id)
|
||||
{
|
||||
sprite.params.glyph_data = Some(new.sprite.clone());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn button_clicked(
|
||||
&mut self,
|
||||
common: &mut CallbackDataCommon,
|
||||
key: &str,
|
||||
) -> Box<ModifyOverlayTask> {
|
||||
self.change_highlight(common, key);
|
||||
|
||||
let state = S::from_tab_key(key);
|
||||
self.on_button_clicked.as_ref().unwrap()(common, &state)
|
||||
}
|
||||
|
||||
pub fn reset(&mut self, common: &mut CallbackDataCommon, state: &S) {
|
||||
let key = state.to_tab_key();
|
||||
self.change_highlight(common, key);
|
||||
}
|
||||
}
|
||||
52
wlx-overlay-s/src/overlays/edit/stereo.rs
Normal file
52
wlx-overlay-s/src/overlays/edit/stereo.rs
Normal file
@@ -0,0 +1,52 @@
|
||||
use crate::{
|
||||
overlays::edit::{
|
||||
sprite_tab::{SpriteTabHandler, SpriteTabKey},
|
||||
EditModeWrapPanel,
|
||||
},
|
||||
windowing::backend::{BackendAttribValue, StereoMode},
|
||||
};
|
||||
|
||||
static STEREO_NAMES: [&str; 5] = ["none", "leftright", "rightleft", "topbottom", "bottomtop"];
|
||||
|
||||
pub fn new_stereo_tab_handler(
|
||||
panel: &mut EditModeWrapPanel,
|
||||
) -> anyhow::Result<SpriteTabHandler<StereoMode>> {
|
||||
SpriteTabHandler::new(
|
||||
panel,
|
||||
"stereo",
|
||||
&STEREO_NAMES,
|
||||
Box::new(|_common, state| {
|
||||
let stereo = state.clone();
|
||||
Box::new(move |app, owc| {
|
||||
owc.backend
|
||||
.set_attrib(app, BackendAttribValue::Stereo(stereo));
|
||||
})
|
||||
}),
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
impl SpriteTabKey for StereoMode {
|
||||
fn to_tab_key(&self) -> &'static str {
|
||||
match self {
|
||||
StereoMode::None => "none",
|
||||
StereoMode::LeftRight => "leftright",
|
||||
StereoMode::RightLeft => "rightleft",
|
||||
StereoMode::TopBottom => "topbottom",
|
||||
StereoMode::BottomTop => "bottomtop",
|
||||
}
|
||||
}
|
||||
|
||||
fn from_tab_key(key: &str) -> Self {
|
||||
match key {
|
||||
"none" => StereoMode::None,
|
||||
"leftright" => StereoMode::LeftRight,
|
||||
"rightleft" => StereoMode::RightLeft,
|
||||
"topbottom" => StereoMode::TopBottom,
|
||||
"bottomtop" => StereoMode::BottomTop,
|
||||
_ => {
|
||||
panic!("cannot translate to positioning: {key}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,6 +67,22 @@ impl ButtonPaneTabSwitcher {
|
||||
self.active_tab = Some(data);
|
||||
}
|
||||
|
||||
pub fn set_tab_visible(&mut self, common: &mut CallbackDataCommon, tab: &str, visible: bool) {
|
||||
let Some(data) = self.tabs[tab].button.as_ref() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let display = if visible {
|
||||
taffy::Display::Flex
|
||||
} else {
|
||||
taffy::Display::None
|
||||
};
|
||||
|
||||
common
|
||||
.alterables
|
||||
.set_style(data.get_rect(), StyleSetRequest::Display(display));
|
||||
}
|
||||
|
||||
pub fn reset(&mut self, common: &mut CallbackDataCommon) {
|
||||
if let Some(data) = self.active_tab.take() {
|
||||
set_tab_active(common, &data, false);
|
||||
|
||||
@@ -6,24 +6,27 @@ use std::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
KEYMAP_CHANGE,
|
||||
backend::input::{HoverResult, PointerHit},
|
||||
gui::panel::GuiPanel,
|
||||
overlays::keyboard::{builder::create_keyboard_panel, layout::AltModifier},
|
||||
state::AppState,
|
||||
subsystem::hid::{
|
||||
ALT, CTRL, KeyModifier, META, SHIFT, SUPER, VirtualKey, WheelDelta, XkbKeymap,
|
||||
get_keymap_wl, get_keymap_x11,
|
||||
get_keymap_wl, get_keymap_x11, KeyModifier, VirtualKey, WheelDelta, XkbKeymap, ALT, CTRL,
|
||||
META, SHIFT, SUPER,
|
||||
},
|
||||
windowing::{
|
||||
backend::{FrameMeta, OverlayBackend, OverlayEventData, RenderResources, ShouldRender},
|
||||
backend::{
|
||||
BackendAttrib, BackendAttribValue, FrameMeta, OverlayBackend, OverlayEventData,
|
||||
RenderResources, ShouldRender,
|
||||
},
|
||||
window::OverlayWindowConfig,
|
||||
},
|
||||
KEYMAP_CHANGE,
|
||||
};
|
||||
use anyhow::Context;
|
||||
use glam::{Affine3A, Quat, Vec3, vec3};
|
||||
use glam::{vec3, Affine3A, Quat, Vec3};
|
||||
use regex::Regex;
|
||||
use slotmap::{SlotMap, new_key_type};
|
||||
use slotmap::{new_key_type, SlotMap};
|
||||
use wgui::{
|
||||
drawing,
|
||||
event::{InternalStateChangeEvent, MouseButton, MouseButtonIndex},
|
||||
@@ -279,6 +282,12 @@ impl OverlayBackend for KeyboardBackend {
|
||||
fn get_interaction_transform(&mut self) -> Option<glam::Affine2> {
|
||||
self.panel().get_interaction_transform()
|
||||
}
|
||||
fn get_attrib(&self, _attrib: BackendAttrib) -> Option<BackendAttribValue> {
|
||||
None
|
||||
}
|
||||
fn set_attrib(&mut self, _app: &mut AppState, _value: BackendAttribValue) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
struct KeyboardState {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
use std::{
|
||||
sync::{
|
||||
Arc,
|
||||
atomic::{AtomicUsize, Ordering},
|
||||
Arc,
|
||||
},
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
use futures::{Future, FutureExt};
|
||||
use glam::{Affine2, Affine3A, Quat, Vec3, vec3};
|
||||
use wlx_capture::pipewire::{PipewireCapture, PipewireSelectScreenResult, pipewire_select_screen};
|
||||
use glam::{vec3, Affine2, Affine3A, Quat, Vec3};
|
||||
use wlx_capture::pipewire::{pipewire_select_screen, PipewireCapture, PipewireSelectScreenResult};
|
||||
use wlx_common::windowing::OverlayWindowState;
|
||||
|
||||
use crate::{
|
||||
@@ -19,12 +19,12 @@ use crate::{
|
||||
state::{AppSession, AppState},
|
||||
subsystem::hid::WheelDelta,
|
||||
windowing::{
|
||||
OverlaySelector,
|
||||
backend::{
|
||||
FrameMeta, OverlayBackend, OverlayEventData, RenderResources, ShouldRender,
|
||||
ui_transform,
|
||||
ui_transform, BackendAttrib, BackendAttribValue, FrameMeta, OverlayBackend,
|
||||
OverlayEventData, RenderResources, ShouldRender,
|
||||
},
|
||||
window::{OverlayCategory, OverlayWindowConfig},
|
||||
OverlaySelector,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -152,6 +152,20 @@ impl OverlayBackend for MirrorBackend {
|
||||
fn get_interaction_transform(&mut self) -> Option<Affine2> {
|
||||
self.interaction_transform
|
||||
}
|
||||
fn get_attrib(&self, attrib: BackendAttrib) -> Option<BackendAttribValue> {
|
||||
if let Some(renderer) = self.renderer.as_ref() {
|
||||
renderer.get_attrib(attrib)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
fn set_attrib(&mut self, app: &mut AppState, value: BackendAttribValue) -> bool {
|
||||
if let Some(renderer) = self.renderer.as_mut() {
|
||||
renderer.set_attrib(app, value)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_mirror_name() -> Arc<str> {
|
||||
|
||||
@@ -1,22 +1,26 @@
|
||||
use std::{
|
||||
sync::{Arc, LazyLock, atomic::AtomicU64},
|
||||
sync::{atomic::AtomicU64, Arc, LazyLock},
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
use glam::{Affine2, Vec2, vec2};
|
||||
use wlx_capture::{WlxCapture, frame::Transform};
|
||||
use glam::{vec2, Affine2, Vec2};
|
||||
use wlx_capture::{frame::Transform, WlxCapture};
|
||||
|
||||
use crate::{
|
||||
backend::input::{HoverResult, PointerHit, PointerMode},
|
||||
backend::{
|
||||
input::{HoverResult, PointerHit, PointerMode},
|
||||
XrBackend,
|
||||
},
|
||||
graphics::ExtentExt,
|
||||
state::AppState,
|
||||
subsystem::hid::{MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT, WheelDelta},
|
||||
subsystem::hid::{WheelDelta, MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT},
|
||||
windowing::backend::{
|
||||
FrameMeta, OverlayBackend, OverlayEventData, RenderResources, ShouldRender,
|
||||
BackendAttrib, BackendAttribValue, FrameMeta, OverlayBackend, OverlayEventData,
|
||||
RenderResources, ShouldRender, StereoMode,
|
||||
},
|
||||
};
|
||||
|
||||
use super::capture::{ScreenPipeline, WlxCaptureIn, WlxCaptureOut, receive_callback};
|
||||
use super::capture::{receive_callback, ScreenPipeline, WlxCaptureIn, WlxCaptureOut};
|
||||
|
||||
const CURSOR_SIZE: f32 = 16. / 1440.;
|
||||
|
||||
@@ -42,6 +46,7 @@ pub struct ScreenBackend {
|
||||
meta: Option<FrameMeta>,
|
||||
mouse_transform: Affine2,
|
||||
interaction_transform: Option<Affine2>,
|
||||
stereo: Option<StereoMode>,
|
||||
}
|
||||
|
||||
impl ScreenBackend {
|
||||
@@ -57,6 +62,7 @@ impl ScreenBackend {
|
||||
meta: None,
|
||||
mouse_transform: Affine2::ZERO,
|
||||
interaction_transform: None,
|
||||
stereo: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +109,12 @@ impl ScreenBackend {
|
||||
}
|
||||
|
||||
impl OverlayBackend for ScreenBackend {
|
||||
fn init(&mut self, _app: &mut AppState) -> anyhow::Result<()> {
|
||||
fn init(&mut self, app: &mut AppState) -> anyhow::Result<()> {
|
||||
self.stereo = if matches!(app.xr_backend, XrBackend::OpenXR) {
|
||||
Some(StereoMode::None)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
fn should_render(&mut self, app: &mut AppState) -> anyhow::Result<ShouldRender> {
|
||||
@@ -155,10 +166,14 @@ impl OverlayBackend for ScreenBackend {
|
||||
}
|
||||
|
||||
if let Some(frame) = self.capture.receive() {
|
||||
let meta = frame.get_frame_meta(&app.session.config);
|
||||
let mut meta = frame.get_frame_meta(&app.session.config);
|
||||
|
||||
if let Some(pipeline) = self.pipeline.as_mut() {
|
||||
if self.meta.is_some_and(|old| old.extent != meta.extent) {
|
||||
meta.extent[2] = pipeline.get_depth();
|
||||
if self
|
||||
.meta
|
||||
.is_some_and(|old| old.extent[..2] != meta.extent[..2])
|
||||
{
|
||||
pipeline.set_extent(app, [meta.extent[0] as _, meta.extent[1] as _])?;
|
||||
self.set_interaction_transform(
|
||||
meta.extent.extent_vec2(),
|
||||
@@ -166,7 +181,10 @@ impl OverlayBackend for ScreenBackend {
|
||||
);
|
||||
}
|
||||
} else {
|
||||
self.pipeline = Some(ScreenPipeline::new(&meta, app)?);
|
||||
let pipeline =
|
||||
ScreenPipeline::new(&meta, app, self.stereo.unwrap_or(StereoMode::None))?;
|
||||
meta.extent[2] = pipeline.get_depth();
|
||||
self.pipeline = Some(pipeline);
|
||||
self.set_interaction_transform(meta.extent.extent_vec2(), frame.get_transform());
|
||||
}
|
||||
|
||||
@@ -259,4 +277,29 @@ impl OverlayBackend for ScreenBackend {
|
||||
fn get_interaction_transform(&mut self) -> Option<Affine2> {
|
||||
self.interaction_transform
|
||||
}
|
||||
#[allow(unreachable_patterns)]
|
||||
fn get_attrib(&self, attrib: BackendAttrib) -> Option<BackendAttribValue> {
|
||||
match attrib {
|
||||
BackendAttrib::Stereo => self.stereo.map(|s| BackendAttribValue::Stereo(s)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
#[allow(unreachable_patterns)]
|
||||
fn set_attrib(&mut self, app: &mut AppState, value: BackendAttribValue) -> bool {
|
||||
match value {
|
||||
BackendAttribValue::Stereo(new) => {
|
||||
if let Some(stereo) = self.stereo.as_mut() {
|
||||
log::debug!("{}: stereo: {stereo:?} → {new:?}", self.name);
|
||||
*stereo = new;
|
||||
if let Some(pipeline) = self.pipeline.as_mut() {
|
||||
pipeline.set_stereo(app, new).unwrap(); // only panics if gfx is dead
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,54 +1,58 @@
|
||||
use std::{f32::consts::PI, sync::Arc};
|
||||
|
||||
use glam::{Affine3A, Vec3};
|
||||
use smallvec::smallvec;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use vulkano::{
|
||||
buffer::{BufferUsage, Subbuffer},
|
||||
command_buffer::CommandBufferUsage,
|
||||
device::Queue,
|
||||
format::Format,
|
||||
image::{Image, sampler::Filter, view::ImageView},
|
||||
image::{sampler::Filter, view::ImageView, Image},
|
||||
pipeline::graphics::color_blend::AttachmentBlend,
|
||||
};
|
||||
use wgui::gfx::{
|
||||
WGfx,
|
||||
cmd::WGfxClearMode,
|
||||
pass::WGfxPass,
|
||||
pipeline::{WGfxPipeline, WPipelineCreateInfo},
|
||||
WGfx,
|
||||
};
|
||||
use wlx_capture::{
|
||||
WlxCapture,
|
||||
frame::{self as wlx_frame, DrmFormat, FrameFormat, MouseMeta, Transform, WlxFrame},
|
||||
WlxCapture,
|
||||
};
|
||||
use wlx_common::config::GeneralConfig;
|
||||
|
||||
use crate::{
|
||||
graphics::{
|
||||
Vert2Uv,
|
||||
dmabuf::{WGfxDmabuf, fourcc_to_vk},
|
||||
upload_quad_vertices,
|
||||
dmabuf::{fourcc_to_vk, WGfxDmabuf},
|
||||
upload_quad_vertices, Vert2Uv,
|
||||
},
|
||||
state::AppState,
|
||||
windowing::backend::{FrameMeta, RenderResources},
|
||||
windowing::backend::{FrameMeta, RenderResources, StereoMode},
|
||||
};
|
||||
|
||||
const CURSOR_SIZE: f32 = 16. / 1440.;
|
||||
|
||||
struct MousePass {
|
||||
struct BufPass {
|
||||
pass: WGfxPass<Vert2Uv>,
|
||||
buf_vert: Subbuffer<[Vert2Uv]>,
|
||||
}
|
||||
|
||||
pub(super) struct ScreenPipeline {
|
||||
mouse: MousePass,
|
||||
mouse: BufPass,
|
||||
pass: SmallVec<[BufPass; 2]>,
|
||||
pipeline: Arc<WGfxPipeline<Vert2Uv>>,
|
||||
pass: WGfxPass<Vert2Uv>,
|
||||
buf_alpha: Subbuffer<[f32]>,
|
||||
extentf: [f32; 2],
|
||||
stereo: StereoMode,
|
||||
}
|
||||
|
||||
impl ScreenPipeline {
|
||||
pub(super) fn new(meta: &FrameMeta, app: &mut AppState) -> anyhow::Result<Self> {
|
||||
pub(super) fn new(
|
||||
meta: &FrameMeta,
|
||||
app: &mut AppState,
|
||||
stereo: StereoMode,
|
||||
) -> anyhow::Result<Self> {
|
||||
let extentf = [meta.extent[0] as f32, meta.extent[1] as f32];
|
||||
|
||||
let pipeline = app.gfx.create_pipeline(
|
||||
@@ -63,17 +67,61 @@ impl ScreenPipeline {
|
||||
.gfx
|
||||
.empty_buffer(BufferUsage::TRANSFER_DST | BufferUsage::UNIFORM_BUFFER, 1)?;
|
||||
|
||||
Ok(Self {
|
||||
pass: Self::create_pass(app, pipeline.clone(), extentf, buf_alpha.clone())?,
|
||||
let mut me = Self {
|
||||
pass: smallvec![Self::create_pass(
|
||||
app,
|
||||
pipeline.clone(),
|
||||
extentf,
|
||||
buf_alpha.clone()
|
||||
)?],
|
||||
mouse: Self::create_mouse_pass(app, pipeline.clone(), extentf, buf_alpha.clone())?,
|
||||
pipeline,
|
||||
extentf,
|
||||
buf_alpha,
|
||||
})
|
||||
stereo,
|
||||
};
|
||||
me.set_stereo(app, stereo)?;
|
||||
Ok(me)
|
||||
}
|
||||
|
||||
pub fn set_stereo(&mut self, app: &mut AppState, stereo: StereoMode) -> anyhow::Result<()> {
|
||||
let depth = if matches!(stereo, StereoMode::None) {
|
||||
1
|
||||
} else {
|
||||
2
|
||||
};
|
||||
|
||||
if self.pass.len() < depth {
|
||||
self.pass.push(Self::create_pass(
|
||||
app,
|
||||
self.pipeline.clone(),
|
||||
self.extentf,
|
||||
self.buf_alpha.clone(),
|
||||
)?);
|
||||
}
|
||||
|
||||
if self.pass.len() > depth {
|
||||
self.pass.pop();
|
||||
}
|
||||
|
||||
for (eye, current) in self.pass.iter_mut().enumerate() {
|
||||
let verts = stereo_mode_to_verts(stereo, eye);
|
||||
current.buf_vert.write()?.copy_from_slice(&verts);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_depth(&self) -> u32 {
|
||||
self.pass.len() as _
|
||||
}
|
||||
|
||||
pub fn set_extent(&mut self, app: &mut AppState, extentf: [f32; 2]) -> anyhow::Result<()> {
|
||||
self.pass = Self::create_pass(app, self.pipeline.clone(), extentf, self.buf_alpha.clone())?;
|
||||
for (eye, pass) in self.pass.iter_mut().enumerate() {
|
||||
*pass = Self::create_pass(app, self.pipeline.clone(), extentf, self.buf_alpha.clone())?;
|
||||
let verts = stereo_mode_to_verts(self.stereo, eye);
|
||||
pass.buf_vert.write()?.copy_from_slice(&verts);
|
||||
}
|
||||
|
||||
self.mouse =
|
||||
Self::create_mouse_pass(app, self.pipeline.clone(), extentf, self.buf_alpha.clone())?;
|
||||
Ok(())
|
||||
@@ -84,21 +132,27 @@ impl ScreenPipeline {
|
||||
pipeline: Arc<WGfxPipeline<Vert2Uv>>,
|
||||
extentf: [f32; 2],
|
||||
buf_alpha: Subbuffer<[f32]>,
|
||||
) -> anyhow::Result<WGfxPass<Vert2Uv>> {
|
||||
) -> anyhow::Result<BufPass> {
|
||||
let set0 = pipeline.uniform_sampler(
|
||||
0,
|
||||
app.gfx_extras.fallback_image.clone(),
|
||||
app.gfx.texture_filter,
|
||||
)?;
|
||||
let set1 = pipeline.buffer(1, buf_alpha)?;
|
||||
pipeline.create_pass(
|
||||
let buf_vert = app
|
||||
.gfx
|
||||
.empty_buffer(BufferUsage::TRANSFER_DST | BufferUsage::VERTEX_BUFFER, 4)?;
|
||||
|
||||
let pass = pipeline.create_pass(
|
||||
extentf,
|
||||
app.gfx_extras.quad_verts.clone(),
|
||||
buf_vert.clone(),
|
||||
0..4,
|
||||
0..1,
|
||||
vec![set0, set1],
|
||||
&Default::default(),
|
||||
)
|
||||
)?;
|
||||
|
||||
Ok(BufPass { pass, buf_vert })
|
||||
}
|
||||
|
||||
fn create_mouse_pass(
|
||||
@@ -106,7 +160,7 @@ impl ScreenPipeline {
|
||||
pipeline: Arc<WGfxPipeline<Vert2Uv>>,
|
||||
extentf: [f32; 2],
|
||||
buf_alpha: Subbuffer<[f32]>,
|
||||
) -> anyhow::Result<MousePass> {
|
||||
) -> anyhow::Result<BufPass> {
|
||||
#[rustfmt::skip]
|
||||
let mouse_bytes = [
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
|
||||
@@ -140,7 +194,7 @@ impl ScreenPipeline {
|
||||
)?;
|
||||
|
||||
cmd_xfer.build_and_execute_now()?;
|
||||
Ok(MousePass { pass, buf_vert })
|
||||
Ok(BufPass { pass, buf_vert })
|
||||
}
|
||||
|
||||
pub(super) fn render(
|
||||
@@ -150,33 +204,103 @@ impl ScreenPipeline {
|
||||
rdr: &mut RenderResources,
|
||||
) -> anyhow::Result<()> {
|
||||
let view = ImageView::new_default(capture.image.clone())?;
|
||||
|
||||
self.pass.update_sampler(0, view, app.gfx.texture_filter)?;
|
||||
self.buf_alpha.write()?[0] = rdr.alpha;
|
||||
|
||||
rdr.cmd_buf.run_ref(&self.pass)?;
|
||||
for (eye, cmd_buf) in rdr.cmd_bufs.iter_mut().enumerate() {
|
||||
let current = &mut self.pass[eye];
|
||||
|
||||
if let Some(mouse) = capture.mouse.as_ref() {
|
||||
let size = CURSOR_SIZE * self.extentf[1];
|
||||
let half_size = size * 0.5;
|
||||
current
|
||||
.pass
|
||||
.update_sampler(0, view.clone(), app.gfx.texture_filter)?;
|
||||
|
||||
upload_quad_vertices(
|
||||
&mut self.mouse.buf_vert,
|
||||
self.extentf[0],
|
||||
self.extentf[1],
|
||||
mouse.x.mul_add(self.extentf[0], -half_size),
|
||||
mouse.y.mul_add(self.extentf[1], -half_size),
|
||||
size,
|
||||
size,
|
||||
)?;
|
||||
cmd_buf.run_ref(¤t.pass)?;
|
||||
|
||||
rdr.cmd_buf.run_ref(&self.mouse.pass)?;
|
||||
if let Some(mouse) = capture.mouse.as_ref() {
|
||||
let size = CURSOR_SIZE * self.extentf[1];
|
||||
let half_size = size * 0.5;
|
||||
|
||||
upload_quad_vertices(
|
||||
&mut self.mouse.buf_vert,
|
||||
self.extentf[0],
|
||||
self.extentf[1],
|
||||
mouse.x.mul_add(self.extentf[0], -half_size),
|
||||
mouse.y.mul_add(self.extentf[1], -half_size),
|
||||
size,
|
||||
size,
|
||||
)?;
|
||||
|
||||
cmd_buf.run_ref(&self.mouse.pass)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn stereo_mode_to_verts(stereo: StereoMode, array_index: usize) -> [Vert2Uv; 4] {
|
||||
let eye = match stereo {
|
||||
StereoMode::RightLeft | StereoMode::BottomTop => (1 - array_index) as f32,
|
||||
_ => array_index as f32,
|
||||
};
|
||||
|
||||
match stereo {
|
||||
StereoMode::None => [
|
||||
Vert2Uv {
|
||||
in_pos: [0., 0.],
|
||||
in_uv: [0., 0.],
|
||||
},
|
||||
Vert2Uv {
|
||||
in_pos: [1., 0.],
|
||||
in_uv: [1., 0.],
|
||||
},
|
||||
Vert2Uv {
|
||||
in_pos: [0., 1.],
|
||||
in_uv: [0., 1.],
|
||||
},
|
||||
Vert2Uv {
|
||||
in_pos: [1., 1.],
|
||||
in_uv: [1., 1.],
|
||||
},
|
||||
],
|
||||
StereoMode::LeftRight | StereoMode::RightLeft => [
|
||||
Vert2Uv {
|
||||
in_pos: [0., 0.],
|
||||
in_uv: [eye * 0.5, 0.],
|
||||
},
|
||||
Vert2Uv {
|
||||
in_pos: [1., 0.],
|
||||
in_uv: [0.5 + eye * 0.5, 0.],
|
||||
},
|
||||
Vert2Uv {
|
||||
in_pos: [0., 1.],
|
||||
in_uv: [eye * 0.5, 1.],
|
||||
},
|
||||
Vert2Uv {
|
||||
in_pos: [1., 1.],
|
||||
in_uv: [0.5 + eye * 0.5, 1.],
|
||||
},
|
||||
],
|
||||
StereoMode::TopBottom | StereoMode::BottomTop => [
|
||||
Vert2Uv {
|
||||
in_pos: [0., 0.],
|
||||
in_uv: [0., eye * 0.5],
|
||||
},
|
||||
Vert2Uv {
|
||||
in_pos: [1., 0.],
|
||||
in_uv: [1., eye * 0.5],
|
||||
},
|
||||
Vert2Uv {
|
||||
in_pos: [0., 1.],
|
||||
in_uv: [0., 0.5 + eye * 0.5],
|
||||
},
|
||||
Vert2Uv {
|
||||
in_pos: [1., 1.],
|
||||
in_uv: [1., 0.5 + eye * 0.5],
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WlxCaptureIn {
|
||||
name: Arc<str>,
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
use anyhow::Context;
|
||||
use glam::{Affine2, Affine3A, Quat, Vec3, vec3};
|
||||
use glam::{vec3, Affine2, Affine3A, Quat, Vec3};
|
||||
use smallvec::smallvec;
|
||||
use std::{cell::RefCell, collections::HashMap, rc::Rc, sync::Arc};
|
||||
use vulkano::{
|
||||
buffer::{BufferUsage, Subbuffer},
|
||||
command_buffer::CommandBufferUsage,
|
||||
format::Format,
|
||||
image::{Image, ImageTiling, SubresourceLayout, view::ImageView},
|
||||
image::{view::ImageView, Image, ImageTiling, SubresourceLayout},
|
||||
};
|
||||
use wayvr_ipc::packet_server::{self, PacketServer, WvrStateChanged};
|
||||
use wgui::gfx::{
|
||||
WGfx,
|
||||
pass::WGfxPass,
|
||||
pipeline::{WGfxPipeline, WPipelineCreateInfo},
|
||||
WGfx,
|
||||
};
|
||||
use wlx_capture::frame::{DmabufFrame, FourCC, FrameFormat, FramePlane};
|
||||
use wlx_common::windowing::OverlayWindowState;
|
||||
@@ -22,22 +22,23 @@ use crate::{
|
||||
input::{self, HoverResult},
|
||||
task::{OverlayTask, TaskType},
|
||||
wayvr::{
|
||||
self, WayVR, WayVRAction, WayVRDisplayClickAction, display,
|
||||
self, display,
|
||||
server_ipc::{gen_args_vec, gen_env_vec},
|
||||
WayVR, WayVRAction, WayVRDisplayClickAction,
|
||||
},
|
||||
},
|
||||
config_wayvr,
|
||||
graphics::{Vert2Uv, dmabuf::WGfxDmabuf},
|
||||
graphics::{dmabuf::WGfxDmabuf, Vert2Uv},
|
||||
state::{self, AppState},
|
||||
subsystem::{hid::WheelDelta, input::KeyboardFocus},
|
||||
windowing::{
|
||||
OverlayID, OverlaySelector, Z_ORDER_DASHBOARD,
|
||||
backend::{
|
||||
FrameMeta, OverlayBackend, OverlayEventData, RenderResources, ShouldRender,
|
||||
ui_transform,
|
||||
ui_transform, BackendAttrib, BackendAttribValue, FrameMeta, OverlayBackend,
|
||||
OverlayEventData, RenderResources, ShouldRender,
|
||||
},
|
||||
manager::OverlayWindowManager,
|
||||
window::{OverlayCategory, OverlayWindowConfig, OverlayWindowData},
|
||||
OverlayID, OverlaySelector, Z_ORDER_DASHBOARD,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -703,7 +704,7 @@ impl OverlayBackend for WayVRBackend {
|
||||
self.pass
|
||||
.update_sampler(0, image.vk_image_view.clone(), self.graphics.texture_filter)?;
|
||||
self.buf_alpha.write()?[0] = rdr.alpha;
|
||||
rdr.cmd_buf.run_ref(&self.pass)?;
|
||||
rdr.cmd_buf_single().run_ref(&self.pass)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -782,6 +783,13 @@ impl OverlayBackend for WayVRBackend {
|
||||
fn get_interaction_transform(&mut self) -> Option<Affine2> {
|
||||
self.interaction_transform
|
||||
}
|
||||
|
||||
fn get_attrib(&self, _attrib: BackendAttrib) -> Option<BackendAttribValue> {
|
||||
None
|
||||
}
|
||||
fn set_attrib(&mut self, _app: &mut AppState, _value: BackendAttribValue) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
||||
Reference in New Issue
Block a user