reworked code
This commit is contained in:
55
src/input.rs
Normal file
55
src/input.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
use bevy::prelude::*;
|
||||
use openxr as xr;
|
||||
|
||||
type XrPose = (Vec3, Quat);
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct XrInput {
|
||||
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,
|
||||
}
|
||||
|
||||
impl XrInput {
|
||||
pub fn new(
|
||||
instance: xr::Instance,
|
||||
session: xr::Session<xr::AnyGraphics>,
|
||||
) -> xr::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 {
|
||||
action_set,
|
||||
right_action,
|
||||
left_action,
|
||||
right_space,
|
||||
left_space,
|
||||
stage,
|
||||
})
|
||||
}
|
||||
}
|
||||
130
src/lib.rs
130
src/lib.rs
@@ -1,52 +1,118 @@
|
||||
pub mod input;
|
||||
pub mod resource_macros;
|
||||
pub mod resources;
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use bevy::ecs::system::SystemState;
|
||||
use bevy::prelude::*;
|
||||
use bevy::render::settings::WgpuSettings;
|
||||
use bevy::render::FutureRendererResources;
|
||||
use bevy::render::{FutureRendererResources, RenderPlugin, renderer};
|
||||
use bevy::window::{PrimaryWindow, RawHandleWrapper};
|
||||
use state::XrState;
|
||||
use input::XrInput;
|
||||
use resources::*;
|
||||
|
||||
mod state;
|
||||
|
||||
pub struct OpenXrPlugin {
|
||||
pub wgpu_settings: WgpuSettings,
|
||||
}
|
||||
/// Adds OpenXR support to an App
|
||||
#[derive(Default)]
|
||||
pub struct OpenXrPlugin;
|
||||
|
||||
#[derive(Resource)]
|
||||
struct FutureXrResources (
|
||||
Arc<
|
||||
pub struct FutureXrResources(
|
||||
pub Arc<
|
||||
Mutex<
|
||||
Option<
|
||||
XrState
|
||||
>
|
||||
>
|
||||
>
|
||||
Option<(
|
||||
XrInstance,
|
||||
XrSession,
|
||||
XrEnvironmentBlendMode,
|
||||
XrSessionRunning,
|
||||
XrFrameWaiter,
|
||||
XrSwapchain,
|
||||
XrInput,
|
||||
)>,
|
||||
>,
|
||||
>,
|
||||
);
|
||||
|
||||
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(),
|
||||
));
|
||||
let future_renderer_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 future_xr_resources_wrapper = Arc::new(Mutex::new(None));
|
||||
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 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();
|
||||
let settings = WgpuSettings::default();
|
||||
bevy::tasks::IoTaskPool::get()
|
||||
.spawn_local(async move {
|
||||
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
||||
backends: settings.backends.unwrap(),
|
||||
dx12_shader_compiler: settings.dx12_shader_compiler.clone(),
|
||||
});
|
||||
let surface = primary_window.map(|wrapper| unsafe {
|
||||
// SAFETY: Plugins should be set up on the main thread.
|
||||
let handle = wrapper.get_handle();
|
||||
instance
|
||||
.create_surface(&handle)
|
||||
.expect("Failed to create wgpu surface")
|
||||
});
|
||||
|
||||
let request_adapter_options = wgpu::RequestAdapterOptions {
|
||||
power_preference: settings.power_preference,
|
||||
compatible_surface: surface.as_ref(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let (device, queue, adapter_info, render_adapter) =
|
||||
renderer::initialize_renderer(&instance, &settings, &request_adapter_options)
|
||||
.await;
|
||||
debug!("Configured wgpu adapter Limits: {:#?}", device.limits());
|
||||
debug!("Configured wgpu adapter Features: {:#?}", device.features());
|
||||
let mut future_renderer_resources_inner =
|
||||
future_renderer_resources_wrapper.lock().unwrap();
|
||||
*future_renderer_resources_inner =
|
||||
Some((device, queue, adapter_info, render_adapter, instance));
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
fn ready(&self, app: &App) -> bool {
|
||||
app.world
|
||||
.get_resource::<FutureXrResources>()
|
||||
.and_then(|frr| frr.0.try_lock().map(|locked| locked.is_some()).ok())
|
||||
.unwrap_or(true)
|
||||
}
|
||||
|
||||
fn finish(&self, app: &mut App) {
|
||||
if let Some(future_renderer_resources) =
|
||||
app.world.remove_resource::<FutureXrResources>()
|
||||
{
|
||||
let (instance, session, blend_mode, session_running, frame_waiter, swapchain, input) =
|
||||
future_renderer_resources.0.lock().unwrap().take().unwrap();
|
||||
|
||||
app.insert_resource(instance.clone())
|
||||
.insert_resource(session.clone())
|
||||
.insert_resource(blend_mode.clone())
|
||||
.insert_resource(session_running.clone())
|
||||
.insert_resource(frame_waiter.clone())
|
||||
.insert_resource(swapchain.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DefaultXrPlugins;
|
||||
|
||||
impl PluginGroup for DefaultXrPlugins {
|
||||
fn build(self) -> bevy::app::PluginGroupBuilder {
|
||||
DefaultPlugins
|
||||
.build()
|
||||
.add_before::<RenderPlugin, _>(OpenXrPlugin)
|
||||
}
|
||||
}
|
||||
|
||||
58
src/resource_macros.rs
Normal file
58
src/resource_macros.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
#[macro_export]
|
||||
macro_rules! xr_resource_wrapper {
|
||||
($wrapper_type:ident, $xr_type:ty) => {
|
||||
#[derive(Clone, bevy::prelude::Resource)]
|
||||
pub struct $wrapper_type($xr_type);
|
||||
|
||||
impl $wrapper_type {
|
||||
pub fn new(value: $xr_type) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for $wrapper_type {
|
||||
type Target = $xr_type;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$xr_type> for $wrapper_type {
|
||||
fn from(value: $xr_type) -> Self {
|
||||
Self::new(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! xr_arc_resource_wrapper {
|
||||
($wrapper_type:ident, $xr_type:ty) => {
|
||||
#[derive(Clone, bevy::prelude::Resource)]
|
||||
pub struct $wrapper_type(std::sync::Arc<$xr_type>);
|
||||
|
||||
impl $wrapper_type {
|
||||
pub fn new(value: $xr_type) -> Self {
|
||||
Self(std::sync::Arc::new(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for $wrapper_type {
|
||||
type Target = $xr_type;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$xr_type> for $wrapper_type {
|
||||
fn from(value: $xr_type) -> Self {
|
||||
Self::new(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub use xr_resource_wrapper;
|
||||
pub use xr_arc_resource_wrapper;
|
||||
23
src/resources.rs
Normal file
23
src/resources.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
use std::sync::Mutex;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
|
||||
use crate::resource_macros::*;
|
||||
use openxr as xr;
|
||||
|
||||
xr_resource_wrapper!(XrInstance, xr::Instance);
|
||||
xr_resource_wrapper!(XrSession, xr::Session<xr::AnyGraphics>);
|
||||
xr_resource_wrapper!(XrEnvironmentBlendMode, xr::EnvironmentBlendMode);
|
||||
xr_arc_resource_wrapper!(XrSessionRunning, AtomicBool);
|
||||
xr_arc_resource_wrapper!(XrFrameWaiter, Mutex<XrFrameWaiter>);
|
||||
xr_arc_resource_wrapper!(XrSwapchain, Mutex<Swapchain>);
|
||||
|
||||
pub enum Swapchain {
|
||||
Vulkan(SwapchainInner<xr::Vulkan>)
|
||||
}
|
||||
|
||||
pub struct SwapchainInner<G: xr::Graphics> {
|
||||
stream: xr::FrameStream<G>,
|
||||
handle: xr::Swapchain<G>,
|
||||
resolution: (u32, u32),
|
||||
buffers: Vec<wgpu::Texture>,
|
||||
}
|
||||
67
src/state.rs
67
src/state.rs
@@ -1,67 +0,0 @@
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use openxr as xr;
|
||||
use xr::Result as XrResult;
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct XrState {
|
||||
instance: xr::Instance,
|
||||
session: xr::Session<xr::AnyGraphics>,
|
||||
session_running: AtomicBool,
|
||||
event_buffer: xr::EventDataBuffer,
|
||||
views: Vec<xr::ViewConfigurationView>,
|
||||
graphics: XrGraphics,
|
||||
}
|
||||
|
||||
enum XrGraphics {
|
||||
Vulkan(Mutex<XrGraphicsInner<xr::Vulkan>>)
|
||||
}
|
||||
|
||||
impl XrGraphics {
|
||||
fn begin(&self) -> XrResult<xr::FrameState> {
|
||||
match self {
|
||||
XrGraphics::Vulkan(inner) => inner.lock().unwrap().begin(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct XrGraphicsInner<G: xr::Graphics> {
|
||||
wait: xr::FrameWaiter,
|
||||
stream: xr::FrameStream<G>,
|
||||
swapchain: xr::Swapchain<G>,
|
||||
blend_mode: xr::EnvironmentBlendMode,
|
||||
resolution: Extent2D,
|
||||
buffers: Vec<wgpu::Texture>,
|
||||
}
|
||||
|
||||
impl<G: xr::Graphics> XrGraphicsInner<G> {
|
||||
fn begin(&mut self) -> XrResult<xr::FrameState> {
|
||||
let frame_state = self.wait.wait()?;
|
||||
self.stream.begin()?;
|
||||
Ok(frame_state)
|
||||
}
|
||||
|
||||
fn get_render_view(&mut self, layer: u32) -> 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: layer,
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct Extent2D {
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
unsafe impl Sync for XrState {}
|
||||
unsafe impl Send for XrState {}
|
||||
Reference in New Issue
Block a user