mirror of https://github.com/wayvr-org/wayvr.git
Add crop rect support for focused screens
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
parent
18f99b5daf
commit
40128a6d75
|
|
@ -57,11 +57,14 @@ pub struct ScreenBackend {
|
|||
stereo: Option<StereoMode>,
|
||||
stereo_full_frame: bool,
|
||||
stereo_adjust_mouse: bool,
|
||||
crop_rect: [f32; 4],
|
||||
crop_dirty: bool,
|
||||
pub(super) logical_pos: Vec2,
|
||||
pub(super) logical_size: Vec2,
|
||||
pub(super) mouse_transform_original: Transform,
|
||||
mouse_transform_override: MouseTransform,
|
||||
just_resumed: bool,
|
||||
source_meta: Option<FrameMeta>,
|
||||
}
|
||||
|
||||
impl ScreenBackend {
|
||||
|
|
@ -87,17 +90,22 @@ impl ScreenBackend {
|
|||
},
|
||||
stereo_full_frame: false,
|
||||
stereo_adjust_mouse: false,
|
||||
crop_rect: [0.0, 0.0, 1.0, 1.0],
|
||||
crop_dirty: false,
|
||||
logical_pos: Vec2::ZERO,
|
||||
logical_size: Vec2::ZERO,
|
||||
mouse_transform_original: Transform::Undefined,
|
||||
mouse_transform_override: MouseTransform::Default,
|
||||
just_resumed: false,
|
||||
source_meta: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn apply_mouse_transform_with_override(&mut self, override_transform: Transform) {
|
||||
let mut size = self.logical_size;
|
||||
let pos = self.logical_pos;
|
||||
let crop_origin = Vec2::new(self.crop_rect[0], self.crop_rect[1]);
|
||||
let crop_size = Vec2::new(self.crop_rect[2], self.crop_rect[3]);
|
||||
let mut size = self.logical_size * crop_size;
|
||||
let pos = self.logical_pos + self.logical_size * crop_origin;
|
||||
|
||||
if self.stereo_adjust_mouse
|
||||
&& let Some(stereo) = self.stereo.as_ref()
|
||||
|
|
@ -153,6 +161,64 @@ impl ScreenBackend {
|
|||
),
|
||||
};
|
||||
}
|
||||
|
||||
fn effective_extent(&self, source_extent: [u32; 2]) -> [u32; 2] {
|
||||
[
|
||||
(source_extent[0] as f32 * self.crop_rect[2])
|
||||
.round()
|
||||
.max(1.0) as u32,
|
||||
(source_extent[1] as f32 * self.crop_rect[3])
|
||||
.round()
|
||||
.max(1.0) as u32,
|
||||
]
|
||||
}
|
||||
|
||||
fn apply_meta_state(
|
||||
&mut self,
|
||||
app: &mut AppState,
|
||||
mut source_meta: FrameMeta,
|
||||
stereo: StereoMode,
|
||||
) -> anyhow::Result<()> {
|
||||
let source_extent = source_meta.extent;
|
||||
let effective_extent = self.effective_extent(source_extent);
|
||||
source_meta.extent = effective_extent;
|
||||
|
||||
if let Some(pipeline) = self.pipeline.as_mut() {
|
||||
if self
|
||||
.meta
|
||||
.is_some_and(|old| old.extent != source_meta.extent)
|
||||
{
|
||||
pipeline.set_extent(
|
||||
app,
|
||||
[source_meta.extent[0] as f32, source_meta.extent[1] as f32],
|
||||
[0.0, 0.0],
|
||||
[source_extent[0] as f32, source_extent[1] as f32],
|
||||
)?;
|
||||
self.interaction_transform = Some(ui_transform(source_meta.extent));
|
||||
}
|
||||
if self.crop_dirty {
|
||||
pipeline.set_crop_rect(self.crop_rect)?;
|
||||
}
|
||||
pipeline.ensure_stereo(stereo);
|
||||
} else {
|
||||
let pipeline = ScreenPipeline::new(
|
||||
&source_meta,
|
||||
source_extent,
|
||||
app,
|
||||
stereo,
|
||||
[0.0, 0.0],
|
||||
self.crop_rect,
|
||||
)?;
|
||||
self.pipeline = Some(pipeline);
|
||||
self.interaction_transform = Some(ui_transform(source_meta.extent));
|
||||
}
|
||||
|
||||
self.meta = Some(source_meta);
|
||||
self.crop_dirty = false;
|
||||
let frame_transform = mouse_transform_to_transform(self.mouse_transform_override);
|
||||
self.apply_mouse_transform_with_override(frame_transform);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl OverlayBackend for ScreenBackend {
|
||||
|
|
@ -237,26 +303,19 @@ impl OverlayBackend for ScreenBackend {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(pipeline) = self.pipeline.as_mut() {
|
||||
if self.meta.is_some_and(|old| old.extent != meta.extent) {
|
||||
pipeline.set_extent(
|
||||
app,
|
||||
[meta.extent[0] as _, meta.extent[1] as _],
|
||||
[0., 0.],
|
||||
)?;
|
||||
self.interaction_transform = Some(ui_transform(meta.extent));
|
||||
}
|
||||
} else {
|
||||
let pipeline = ScreenPipeline::new(&meta, app, stereo, [0., 0.])?;
|
||||
self.pipeline = Some(pipeline);
|
||||
self.interaction_transform = Some(ui_transform(meta.extent));
|
||||
}
|
||||
|
||||
self.meta = Some(meta);
|
||||
self.source_meta = Some(meta);
|
||||
self.apply_meta_state(app, meta, stereo)?;
|
||||
self.cur_frame = Some(frame);
|
||||
|
||||
Ok(ShouldRender::Should)
|
||||
} else if self.cur_frame.is_some() {
|
||||
if self.crop_dirty
|
||||
&& let Some(source_meta) = self.source_meta
|
||||
{
|
||||
let stereo = self.stereo.unwrap_or(StereoMode::None);
|
||||
self.apply_meta_state(app, source_meta, stereo)?;
|
||||
return Ok(ShouldRender::Should);
|
||||
}
|
||||
if self.just_resumed {
|
||||
self.just_resumed = false;
|
||||
Ok(ShouldRender::Should)
|
||||
|
|
@ -364,6 +423,7 @@ impl OverlayBackend for ScreenBackend {
|
|||
BackendAttrib::StereoAdjustMouse => Some(BackendAttribValue::StereoAdjustMouse(
|
||||
self.stereo_adjust_mouse,
|
||||
)),
|
||||
BackendAttrib::CropRect => Some(BackendAttribValue::CropRect(self.crop_rect)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -397,6 +457,13 @@ impl OverlayBackend for ScreenBackend {
|
|||
self.apply_mouse_transform_with_override(frame_transform);
|
||||
true
|
||||
}
|
||||
BackendAttribValue::CropRect(new) => {
|
||||
self.crop_rect = new;
|
||||
self.crop_dirty = true;
|
||||
let frame_transform = mouse_transform_to_transform(self.mouse_transform_override);
|
||||
self.apply_mouse_transform_with_override(frame_transform);
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,18 +54,23 @@ pub struct ScreenPipeline {
|
|||
pass: SmallVec<[BufPass; 2]>,
|
||||
pipeline: Arc<WGfxPipeline<Vert2Uv>>,
|
||||
extentf: [f32; 2],
|
||||
source_extentf: [f32; 2],
|
||||
offsetf: [f32; 2],
|
||||
crop_rect: [f32; 4],
|
||||
stereo: StereoMode,
|
||||
}
|
||||
|
||||
impl ScreenPipeline {
|
||||
pub fn new(
|
||||
meta: &FrameMeta,
|
||||
source_extent: [u32; 2],
|
||||
app: &mut AppState,
|
||||
stereo: StereoMode,
|
||||
offsetf: [f32; 2],
|
||||
crop_rect: [f32; 4],
|
||||
) -> anyhow::Result<Self> {
|
||||
let extentf = [meta.extent[0] as f32, meta.extent[1] as f32];
|
||||
let source_extentf = [source_extent[0] as f32, source_extent[1] as f32];
|
||||
|
||||
let pipeline = app.gfx.create_pipeline(
|
||||
app.gfx_extras.shaders.get("vert_quad").unwrap(), // want panic
|
||||
|
|
@ -80,7 +85,9 @@ impl ScreenPipeline {
|
|||
mouse: Self::create_mouse_pass(app, pipeline.clone(), extentf, offsetf)?,
|
||||
pipeline,
|
||||
extentf,
|
||||
source_extentf,
|
||||
offsetf,
|
||||
crop_rect,
|
||||
stereo,
|
||||
};
|
||||
me.ensure_stereo(stereo);
|
||||
|
|
@ -110,8 +117,10 @@ impl ScreenPipeline {
|
|||
self.pass.pop();
|
||||
}
|
||||
|
||||
let stereo = self.stereo;
|
||||
let crop_rect = self.crop_rect;
|
||||
for (eye, current) in self.pass.iter_mut().enumerate() {
|
||||
let verts = stereo_mode_to_verts(self.stereo, eye);
|
||||
let verts = cropped_stereo_mode_to_verts(stereo, crop_rect, eye);
|
||||
current.buf_vert.write()?.copy_from_slice(&verts);
|
||||
}
|
||||
Ok(())
|
||||
|
|
@ -122,8 +131,10 @@ impl ScreenPipeline {
|
|||
app: &mut AppState,
|
||||
extentf: [f32; 2],
|
||||
offsetf: [f32; 2],
|
||||
source_extentf: [f32; 2],
|
||||
) -> anyhow::Result<()> {
|
||||
self.extentf = extentf;
|
||||
self.source_extentf = source_extentf;
|
||||
self.offsetf = offsetf;
|
||||
self.pass.clear();
|
||||
|
||||
|
|
@ -131,6 +142,16 @@ impl ScreenPipeline {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_crop_rect(&mut self, crop_rect: [f32; 4]) -> anyhow::Result<()> {
|
||||
self.crop_rect = crop_rect;
|
||||
let stereo = self.stereo;
|
||||
for (eye, current) in self.pass.iter_mut().enumerate() {
|
||||
let verts = cropped_stereo_mode_to_verts(stereo, crop_rect, eye);
|
||||
current.buf_vert.write()?.copy_from_slice(&verts);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_pass(
|
||||
app: &mut AppState,
|
||||
pipeline: Arc<WGfxPipeline<Vert2Uv>>,
|
||||
|
|
@ -220,15 +241,26 @@ impl ScreenPipeline {
|
|||
cmd_buf.run_ref(¤t.pass)?;
|
||||
|
||||
if let Some(mouse) = mouse.as_ref() {
|
||||
let size = CURSOR_SIZE * self.extentf[1];
|
||||
let [crop_x, crop_y, crop_w, crop_h] = self.crop_rect;
|
||||
if mouse.x < crop_x
|
||||
|| mouse.x > crop_x + crop_w
|
||||
|| mouse.y < crop_y
|
||||
|| mouse.y > crop_y + crop_h
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let local_mouse_x = (mouse.x - crop_x) / crop_w;
|
||||
let local_mouse_y = (mouse.y - crop_y) / crop_h;
|
||||
let size = CURSOR_SIZE * self.source_extentf[1] / crop_h.max(0.01);
|
||||
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),
|
||||
local_mouse_x.mul_add(self.extentf[0], -half_size),
|
||||
local_mouse_y.mul_add(self.extentf[1], -half_size),
|
||||
size,
|
||||
size,
|
||||
)?;
|
||||
|
|
@ -241,6 +273,21 @@ impl ScreenPipeline {
|
|||
}
|
||||
}
|
||||
|
||||
fn cropped_stereo_mode_to_verts(
|
||||
stereo: StereoMode,
|
||||
crop_rect: [f32; 4],
|
||||
array_index: usize,
|
||||
) -> [Vert2Uv; 4] {
|
||||
let [crop_x, crop_y, crop_w, crop_h] = crop_rect;
|
||||
stereo_mode_to_verts(stereo, array_index).map(|vert| Vert2Uv {
|
||||
in_pos: vert.in_pos,
|
||||
in_uv: [
|
||||
crop_x + vert.in_uv[0] * crop_w,
|
||||
crop_y + vert.in_uv[1] * crop_h,
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -352,6 +352,7 @@ impl OverlayBackend for WvrWindowBackend {
|
|||
app,
|
||||
[inner_extent[0] as _, inner_extent[1] as _],
|
||||
[BORDER_SIZE as _, (BAR_SIZE + BORDER_SIZE) as _],
|
||||
[inner_extent[0] as _, inner_extent[1] as _],
|
||||
)?;
|
||||
self.apply_extent(app, &meta)?;
|
||||
self.inner_extent = inner_extent;
|
||||
|
|
@ -359,9 +360,11 @@ impl OverlayBackend for WvrWindowBackend {
|
|||
} else {
|
||||
let pipeline = ScreenPipeline::new(
|
||||
&meta,
|
||||
inner_extent,
|
||||
app,
|
||||
self.stereo.unwrap_or(StereoMode::None),
|
||||
[BORDER_SIZE as _, (BAR_SIZE + BORDER_SIZE) as _],
|
||||
[0.0, 0.0, 1.0, 1.0],
|
||||
)?;
|
||||
self.apply_extent(app, &meta)?;
|
||||
self.pipeline = Some(pipeline);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ pub enum BackendAttrib {
|
|||
StereoFullFrame,
|
||||
StereoAdjustMouse,
|
||||
MouseTransform,
|
||||
CropRect,
|
||||
Icon,
|
||||
}
|
||||
|
||||
|
|
@ -34,6 +35,7 @@ pub enum BackendAttribValue {
|
|||
StereoFullFrame(bool),
|
||||
StereoAdjustMouse(bool),
|
||||
MouseTransform(MouseTransform),
|
||||
CropRect([f32; 4]),
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
Icon(Arc<str>),
|
||||
}
|
||||
|
|
@ -45,6 +47,7 @@ impl BackendAttribValue {
|
|||
Self::StereoFullFrame(val) => !*val,
|
||||
Self::StereoAdjustMouse(val) => !*val,
|
||||
Self::MouseTransform(val) => *val == MouseTransform::default(),
|
||||
Self::CropRect(val) => *val == [0.0, 0.0, 1.0, 1.0],
|
||||
Self::Icon(_) => false,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue