reworked code

This commit is contained in:
awtterpip
2023-08-22 21:19:41 -05:00
parent 8e393804b5
commit 849c3e6677
10 changed files with 659 additions and 99 deletions

141
srcold/input.rs Normal file
View File

@@ -0,0 +1,141 @@
use std::sync::Mutex;
use glam::{Quat, Vec3};
use openxr as xr;
use crate::xr::{VIEW_TYPE, XrPose};
#[derive(Clone)]
pub struct PostFrameData {
pub views: Vec<xr::View>,
pub left_hand: Option<XrPose>,
pub right_hand: Option<XrPose>,
}
pub(crate) struct XrInput {
session: xr::Session<xr::Vulkan>,
action_set: xr::ActionSet,
right_action: xr::Action<xr::Posef>,
left_action: xr::Action<xr::Posef>,
right_space: xr::Space,
left_space: xr::Space,
stage: xr::Space,
left_hand: Mutex<XrPose>,
right_hand: Mutex<XrPose>,
views: Mutex<Vec<XrPose>>,
}
impl XrInput {
pub(crate) fn new(
instance: xr::Instance,
session: xr::Session<xr::Vulkan>,
) -> anyhow::Result<Self> {
let action_set = instance.create_action_set("input", "input pose information", 0)?;
let right_action =
action_set.create_action::<xr::Posef>("right_hand", "Right Hand Controller", &[])?;
let left_action =
action_set.create_action::<xr::Posef>("left_hand", "Left Hand Controller", &[])?;
instance.suggest_interaction_profile_bindings(
instance.string_to_path("/interaction_profiles/khr/simple_controller")?,
&[
xr::Binding::new(
&right_action,
instance.string_to_path("/user/hand/right/input/grip/pose")?,
),
xr::Binding::new(
&left_action,
instance.string_to_path("/user/hand/left/input/grip/pose")?,
),
],
)?;
session.attach_action_sets(&[&action_set])?;
let right_space =
right_action.create_space(session.clone(), xr::Path::NULL, xr::Posef::IDENTITY)?;
let left_space =
left_action.create_space(session.clone(), xr::Path::NULL, xr::Posef::IDENTITY)?;
let stage =
session.create_reference_space(xr::ReferenceSpaceType::STAGE, xr::Posef::IDENTITY)?;
Ok(Self {
left_action,
left_space,
right_action,
right_space,
action_set,
stage,
session,
left_hand: Default::default(),
right_hand: Default::default(),
views: Default::default(),
})
}
pub(crate) fn post_frame(
&self,
xr_frame_state: xr::FrameState,
) -> xr::Result<PostFrameData> {
self.session.sync_actions(&[(&self.action_set).into()])?;
let locate_hand_pose = |action: &xr::Action<xr::Posef>,
space: &xr::Space|
-> xr::Result<Option<(Vec3, Quat)>> {
if action.is_active(&self.session, xr::Path::NULL)? {
Ok(Some(openxr_pose_to_glam(
&space
.locate(&self.stage, xr_frame_state.predicted_display_time)?
.pose,
)))
} else {
Ok(None)
}
};
let left_hand = locate_hand_pose(&self.left_action, &self.left_space)?;
let right_hand = locate_hand_pose(&self.right_action, &self.right_space)?;
let (_, views) = self.session.locate_views(
VIEW_TYPE,
xr_frame_state.predicted_display_time,
&self.stage,
)?;
if let Some(left_hand) = &left_hand {
*self.left_hand.lock().unwrap() = left_hand.clone();
}
if let Some(right_hand) = &left_hand {
*self.right_hand.lock().unwrap() = right_hand.clone();
}
*self.views.lock().unwrap() = views.iter().map(|f| openxr_pose_to_glam(&f.pose)).collect();
Ok(PostFrameData {
views,
left_hand,
right_hand,
})
}
pub fn stage(&self) -> &xr::Space {
&self.stage
}
pub fn left_hand(&self) -> XrPose {
*self.left_hand.lock().unwrap()
}
pub fn right_hand(&self) -> XrPose {
*self.right_hand.lock().unwrap()
}
pub fn views(&self) -> Vec<XrPose> {
self.views.lock().unwrap().clone()
}
}
pub fn openxr_pose_to_glam(pose: &openxr::Posef) -> (Vec3, Quat) {
// with enough sign errors anything is possible
let rotation = {
let o = pose.orientation;
Quat::from_rotation_x(180.0f32.to_radians()) * glam::quat(o.w, o.z, o.y, o.x)
};
let translation = glam::vec3(-pose.position.x, pose.position.y, -pose.position.z);
(translation, rotation)
}

52
srcold/lib.rs Normal file
View File

@@ -0,0 +1,52 @@
use std::sync::{Arc, Mutex};
use bevy::ecs::system::SystemState;
use bevy::prelude::*;
use bevy::render::settings::WgpuSettings;
use bevy::render::FutureRendererResources;
use bevy::window::{PrimaryWindow, RawHandleWrapper};
mod xr;
mod input;
pub struct OpenXrPlugin {
pub wgpu_settings: WgpuSettings,
}
#[derive(Resource)]
struct FutureXrResources (
Arc<
Mutex<
Option<
()
>
>
>
);
impl Plugin for OpenXrPlugin {
fn build(&self, app: &mut App) {
if let Some(backends) = self.wgpu_settings.backends {
let future_renderer_resources_wrapper = Arc::new(Mutex::new(None));
let future_xr_resources_wrapper = Arc::new(Mutex::new(None));
app.insert_resource(FutureRendererResources(
future_renderer_resources_wrapper.clone(),
));
app.insert_resource(FutureXrResources(
future_xr_resources_wrapper.clone(),
));
let mut system_state: SystemState<Query<&RawHandleWrapper, With<PrimaryWindow>>> =
SystemState::new(&mut app.world);
let primary_window = system_state.get(&app.world).get_single().ok().cloned();
let settings = self.wgpu_settings.clone();
bevy::tasks::IoTaskPool::get()
.spawn_local(async move {
})
.detach();
}
}
}

178
srcold/xr/mod.rs Normal file
View File

@@ -0,0 +1,178 @@
use std::cell::UnsafeCell;
use std::sync::atomic::AtomicBool;
use std::sync::Mutex;
use glam::{Quat, Vec3};
use openxr as xr;
use crate::input::{PostFrameData, XrInput};
pub type XrPose = (Vec3, Quat);
pub const VIEW_TYPE: xr::ViewConfigurationType = xr::ViewConfigurationType::PRIMARY_STEREO;
pub enum XrState {
Vulkan(XrStateInner<xr::Vulkan>),
}
pub struct XrStateInner<G: xr::Graphics> {
instance: xr::Instance,
session: xr::Session<G>,
session_running: AtomicBool,
frame: Mutex<FrameInner<G>>,
frame_state: Mutex<Option<xr::FrameState>>,
post_frame_data: Mutex<Option<PostFrameData>>,
event_buffer: UnsafeCell<xr::EventDataBuffer>,
input: XrInput,
}
unsafe impl<G: xr::Graphics> Sync for XrStateInner<G> {}
unsafe impl<G: xr::Graphics> Send for XrStateInner<G> {}
impl<G: xr::Graphics> XrStateInner<G> {
pub fn preframe(&self) -> xr::Result<()> {
let event_buffer = unsafe { &mut *self.event_buffer.get() };
while let Some(event) = self.instance.poll_event(event_buffer)? {
use xr::Event::*;
match event {
SessionStateChanged(e) => {
// Session state change is where we can begin and end sessions, as well as
// find quit messages!
match e.state() {
xr::SessionState::READY => {
self.session
.begin(VIEW_TYPE)?; // TODO! support other view types
self.session_running
.store(true, std::sync::atomic::Ordering::Relaxed);
}
xr::SessionState::STOPPING => {
self.session.end()?;
self.session_running
.store(false, std::sync::atomic::Ordering::Relaxed);
}
xr::SessionState::EXITING | xr::SessionState::LOSS_PENDING => {
*self.frame_state.lock().unwrap() = None;
return Ok(());
}
_ => {}
}
}
InstanceLossPending(_) => {
*self.frame_state.lock().unwrap() = None;
return Ok(());
}
EventsLost(e) => {}
_ => {}
}
}
if !self
.session_running
.load(std::sync::atomic::Ordering::Relaxed)
{
// Don't grind up the CPU
std::thread::sleep(std::time::Duration::from_millis(10));
*self.frame_state.lock().unwrap() = None;
return Ok(());
}
*self.frame_state.lock().unwrap() = Some(self.frame.lock().unwrap().begin()?);
Ok(())
}
pub fn post_frame(&self) -> xr::Result<(wgpu::TextureView, wgpu::TextureView)> {
*self.post_frame_data.lock().unwrap() = Some(self.input.post_frame(self.frame_state.lock().unwrap().unwrap().clone())?);
Ok(self.frame.lock().unwrap().get_render_views())
}
pub fn post_queue_submit(&self) -> xr::Result<()> {
let pfd = self.post_frame_data.lock().unwrap();
self.frame.lock().unwrap().post_queue_submit(self.frame_state.lock().unwrap().unwrap().clone(), &(*pfd).clone().unwrap().views, self.input.stage())
}
}
pub struct FrameInner<G: xr::Graphics> {
waiter: xr::FrameWaiter,
stream: xr::FrameStream<G>,
blend_mode: xr::EnvironmentBlendMode,
views: Vec<xr::ViewConfigurationView>,
swapchain: xr::Swapchain<G>,
resolution: Extent2D,
buffers: Vec<wgpu::Texture>,
}
impl<G: xr::Graphics> FrameInner<G> {
fn begin(&mut self) -> xr::Result<xr::FrameState> {
let frame_state = self.waiter.wait()?;
self.stream.begin()?;
Ok(frame_state)
}
fn get_render_views(&mut self) -> (wgpu::TextureView, wgpu::TextureView) {
let image_index = self.swapchain.acquire_image().unwrap();
self.swapchain.wait_image(xr::Duration::INFINITE).unwrap();
let texture = &self.buffers[image_index as usize];
(
texture.create_view(&wgpu::TextureViewDescriptor {
dimension: Some(wgpu::TextureViewDimension::D2),
array_layer_count: Some(1),
base_array_layer: 0,
..Default::default()
}),
texture.create_view(&wgpu::TextureViewDescriptor {
dimension: Some(wgpu::TextureViewDimension::D2),
array_layer_count: Some(1),
base_array_layer: 1,
..Default::default()
}),
)
}
fn post_queue_submit(
&mut self,
xr_frame_state: xr::FrameState,
views: &[openxr::View],
stage: &xr::Space,
) -> xr::Result<()> {
self.swapchain.release_image()?;
let rect = xr::Rect2Di {
offset: xr::Offset2Di { x: 0, y: 0 },
extent: xr::Extent2Di {
width: self.resolution.width as _,
height: self.resolution.height as _,
},
};
self.stream.end(
xr_frame_state.predicted_display_time,
self.blend_mode,
&[&xr::CompositionLayerProjection::new().space(stage).views(&[
xr::CompositionLayerProjectionView::new()
.pose(views[0].pose)
.fov(views[0].fov)
.sub_image(
xr::SwapchainSubImage::new()
.swapchain(&self.swapchain)
.image_array_index(0)
.image_rect(rect),
),
xr::CompositionLayerProjectionView::new()
.pose(views[1].pose)
.fov(views[1].fov)
.sub_image(
xr::SwapchainSubImage::new()
.swapchain(&self.swapchain)
.image_array_index(1)
.image_rect(rect),
),
])],
)?;
Ok(())
}
}
pub struct Extent2D {
pub width: u32,
pub height: u32,
}