bevy_mod_openxr/openxr/
layer_builder.rs

1use std::mem;
2
3use bevy::ecs::world::World;
4use bevy_mod_xr::spaces::{XrPrimaryReferenceSpace, XrSpace};
5use openxr::{sys, CompositionLayerFlags, Fovf, Posef, Rect2Di};
6
7use crate::graphics::graphics_match;
8use crate::resources::*;
9use crate::spaces::OxrSpaceExt as _;
10
11pub trait LayerProvider {
12    fn get<'a>(&'a self, world: &'a World) -> Option<Box<dyn CompositionLayer<'a> + 'a>>;
13}
14
15pub struct ProjectionLayer;
16
17pub struct PassthroughLayer;
18
19impl LayerProvider for ProjectionLayer {
20    fn get<'a>(&self, world: &'a World) -> Option<Box<dyn CompositionLayer<'a> + 'a>> {
21        let stage = world.get_resource::<XrPrimaryReferenceSpace>()?;
22        let openxr_views = world.get_resource::<OxrViews>()?;
23        let swapchain = world.get_resource::<OxrSwapchain>()?;
24        let graphics_info = world.get_resource::<OxrCurrentSessionConfig>()?;
25        let rect = openxr::Rect2Di {
26            offset: openxr::Offset2Di { x: 0, y: 0 },
27            extent: openxr::Extent2Di {
28                width: graphics_info.resolution.x as _,
29                height: graphics_info.resolution.y as _,
30            },
31        };
32
33        if openxr_views.len() < 2 {
34            return None;
35        }
36
37        Some(Box::new(
38            CompositionLayerProjection::new()
39                .layer_flags(CompositionLayerFlags::BLEND_TEXTURE_SOURCE_ALPHA)
40                .space(stage)
41                .views(&[
42                    CompositionLayerProjectionView::new()
43                        .pose(openxr_views.0[0].pose)
44                        .fov(openxr_views.0[0].fov)
45                        .sub_image(
46                            SwapchainSubImage::new()
47                                .swapchain(swapchain)
48                                .image_array_index(0)
49                                .image_rect(rect),
50                        ),
51                    CompositionLayerProjectionView::new()
52                        .pose(openxr_views.0[1].pose)
53                        .fov(openxr_views.0[1].fov)
54                        .sub_image(
55                            SwapchainSubImage::new()
56                                .swapchain(swapchain)
57                                .image_array_index(1)
58                                .image_rect(rect),
59                        ),
60                ]),
61        ))
62    }
63}
64
65impl LayerProvider for PassthroughLayer {
66    fn get(&self, world: &World) -> Option<Box<dyn CompositionLayer>> {
67        Some(Box::new(
68            CompositionLayerPassthrough::new()
69                .layer_handle(world.get_resource::<OxrPassthroughLayer>()?)
70                .layer_flags(CompositionLayerFlags::BLEND_TEXTURE_SOURCE_ALPHA),
71        ))
72    }
73}
74
75#[derive(Copy, Clone)]
76pub struct SwapchainSubImage<'a> {
77    inner: sys::SwapchainSubImage,
78    swapchain: Option<&'a OxrSwapchain>,
79}
80
81impl<'a> SwapchainSubImage<'a> {
82    #[inline]
83    pub fn new() -> Self {
84        Self {
85            inner: sys::SwapchainSubImage {
86                ..unsafe { mem::zeroed() }
87            },
88            swapchain: None,
89        }
90    }
91    #[inline]
92    pub fn into_raw(self) -> sys::SwapchainSubImage {
93        self.inner
94    }
95    #[inline]
96    pub fn as_raw(&self) -> &sys::SwapchainSubImage {
97        &self.inner
98    }
99    #[inline]
100    pub fn swapchain(mut self, value: &'a OxrSwapchain) -> Self {
101        graphics_match!(
102            &value.0;
103            swap => self.inner.swapchain = swap.as_raw()
104        );
105        self.swapchain = Some(value);
106        self
107    }
108    #[inline]
109    pub fn image_rect(mut self, value: Rect2Di) -> Self {
110        self.inner.image_rect = value;
111        self
112    }
113    #[inline]
114    pub fn image_array_index(mut self, value: u32) -> Self {
115        self.inner.image_array_index = value;
116        self
117    }
118}
119
120impl Default for SwapchainSubImage<'_> {
121    fn default() -> Self {
122        Self::new()
123    }
124}
125
126#[derive(Copy, Clone)]
127pub struct CompositionLayerProjectionView<'a> {
128    inner: sys::CompositionLayerProjectionView,
129    swapchain: Option<&'a OxrSwapchain>,
130}
131
132impl<'a> CompositionLayerProjectionView<'a> {
133    #[inline]
134    pub fn new() -> Self {
135        Self {
136            inner: sys::CompositionLayerProjectionView {
137                ty: sys::StructureType::COMPOSITION_LAYER_PROJECTION_VIEW,
138                ..unsafe { mem::zeroed() }
139            },
140            swapchain: None,
141        }
142    }
143    #[inline]
144    pub fn into_raw(self) -> sys::CompositionLayerProjectionView {
145        self.inner
146    }
147    #[inline]
148    pub fn as_raw(&self) -> &sys::CompositionLayerProjectionView {
149        &self.inner
150    }
151    #[inline]
152    pub fn pose(mut self, value: Posef) -> Self {
153        self.inner.pose = value;
154        self
155    }
156    #[inline]
157    pub fn fov(mut self, value: Fovf) -> Self {
158        self.inner.fov = value;
159        self
160    }
161    #[inline]
162    pub fn sub_image(mut self, value: SwapchainSubImage<'a>) -> Self {
163        self.inner.sub_image = value.inner;
164        self.swapchain = value.swapchain;
165        self
166    }
167}
168impl Default for CompositionLayerProjectionView<'_> {
169    fn default() -> Self {
170        Self::new()
171    }
172}
173/// # Safety
174/// the header function must return a ref to a valid Composition Layer struct. 
175/// it has to use `repr(C)` and it has to follow the shape of a Composition Layer struct from the
176/// OpenXR specification
177pub unsafe trait CompositionLayer<'a> {
178    fn swapchain(&self) -> Option<&'a OxrSwapchain>;
179    fn header(&self) -> &sys::CompositionLayerBaseHeader;
180}
181#[derive(Clone)]
182pub struct CompositionLayerProjection<'a> {
183    inner: sys::CompositionLayerProjection,
184    swapchain: Option<&'a OxrSwapchain>,
185    views: Vec<sys::CompositionLayerProjectionView>,
186}
187impl<'a> CompositionLayerProjection<'a> {
188    #[inline]
189    pub fn new() -> Self {
190        Self {
191            inner: sys::CompositionLayerProjection {
192                ty: sys::StructureType::COMPOSITION_LAYER_PROJECTION,
193                ..unsafe { mem::zeroed() }
194            },
195            swapchain: None,
196            views: Vec::new(),
197        }
198    }
199    #[inline]
200    pub fn into_raw(self) -> sys::CompositionLayerProjection {
201        self.inner
202    }
203    #[inline]
204    pub fn as_raw(&self) -> &sys::CompositionLayerProjection {
205        &self.inner
206    }
207    #[inline]
208    pub fn layer_flags(mut self, value: CompositionLayerFlags) -> Self {
209        self.inner.layer_flags = value;
210        self
211    }
212    #[inline]
213    pub fn space(mut self, value: &XrSpace) -> Self {
214        self.inner.space = value.as_raw_openxr_space();
215        self
216    }
217    #[inline]
218    pub fn views(mut self, value: &[CompositionLayerProjectionView<'a>]) -> Self {
219        self.views = value.iter().map(|view| view.inner).collect();
220        self.inner.views = self.views.as_slice().as_ptr() as *const _ as _;
221        self.inner.view_count = self.views.len() as u32;
222        self
223    }
224}
225unsafe impl<'a> CompositionLayer<'a> for CompositionLayerProjection<'a> {
226    fn swapchain(&self) -> Option<&'a OxrSwapchain> {
227        self.swapchain
228    }
229
230    fn header(&self) -> &sys::CompositionLayerBaseHeader {
231        unsafe { mem::transmute(&self.inner) }
232    }
233}
234impl Default for CompositionLayerProjection<'_> {
235    fn default() -> Self {
236        Self::new()
237    }
238}
239pub struct CompositionLayerPassthrough {
240    inner: sys::CompositionLayerPassthroughFB,
241}
242impl Default for CompositionLayerPassthrough {
243    fn default() -> Self {
244        Self::new()
245    }
246}
247
248impl CompositionLayerPassthrough {
249    #[inline]
250    pub const fn new() -> Self {
251        Self {
252            inner: openxr::sys::CompositionLayerPassthroughFB {
253                ty: openxr::sys::CompositionLayerPassthroughFB::TYPE,
254                ..unsafe { mem::zeroed() }
255            },
256        }
257    }
258    #[inline]
259    pub fn layer_handle(mut self, layer_handle: &OxrPassthroughLayer) -> Self {
260        self.inner.layer_handle = *layer_handle.inner();
261        self
262    }
263    #[inline]
264    pub fn layer_flags(mut self, value: CompositionLayerFlags) -> Self {
265        self.inner.flags = value;
266        self
267    }
268}
269unsafe impl<'a> CompositionLayer<'a> for CompositionLayerPassthrough {
270    fn swapchain(&self) -> Option<&'a OxrSwapchain> {
271        None
272    }
273
274    fn header(&self) -> &sys::CompositionLayerBaseHeader {
275        unsafe { mem::transmute(&self.inner) }
276    }
277}