Compare commits
10 Commits
b339776545
...
7936b53a02
| Author | SHA1 | Date | |
|---|---|---|---|
| 7936b53a02 | |||
|
|
93fe370f12 | ||
|
|
18879e9f06 | ||
|
|
728581d8d7 | ||
|
|
337cfdb3f8 | ||
|
|
93523de2fd | ||
|
|
3974766f7a | ||
|
|
11bf9442e1 | ||
|
|
c8e43c666f | ||
|
|
d94c10c386 |
2
.github/workflows/ci.yaml
vendored
2
.github/workflows/ci.yaml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
- name: Install bevy dependencies
|
||||
run: |
|
||||
sudo apt-get update && sudo apt-get install -y \
|
||||
g++ pkg-config libx11-dev libasound2-dev libudev-dev libopenxr-loader1 libopenxr-dev
|
||||
g++ pkg-config libx11-dev libwayland-dev libasound2-dev libudev-dev libopenxr-loader1 libopenxr-dev
|
||||
|
||||
- name: Cache cargo dependencies
|
||||
uses: Swatinem/rust-cache@v2
|
||||
|
||||
3631
Cargo.lock
generated
3631
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
52
Cargo.toml
52
Cargo.toml
@@ -1,39 +1,41 @@
|
||||
[workspace.package]
|
||||
version = "0.3.0"
|
||||
version = "0.5.0"
|
||||
edition = "2024"
|
||||
description = "Community crate for XR in Bevy"
|
||||
repository = "https://github.com/awtterpip/bevy_oxr"
|
||||
license = "MIT/Apache-2.0"
|
||||
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
resolver = "3"
|
||||
members = ["crates/*", "crates/bevy_openxr/examples/android"]
|
||||
|
||||
[workspace.dependencies]
|
||||
bevy = "0.17"
|
||||
bevy_ecs = { version = "0.17.0", default-features = false }
|
||||
bevy_math = { version = "0.17.0", default-features = false }
|
||||
bevy_render = { version = "0.17.0", default-features = false }
|
||||
bevy_core_pipeline = { version = "0.17.0", default-features = false }
|
||||
bevy_window = { version = "0.17.0", default-features = false }
|
||||
bevy_winit = { version = "0.17.0", default-features = false }
|
||||
bevy_pbr = { version = "0.17.0", default-features = false }
|
||||
bevy_app = { version = "0.17.0", default-features = false }
|
||||
bevy_reflect = { version = "0.17.0", default-features = false }
|
||||
bevy_log = { version = "0.17.0", default-features = false }
|
||||
bevy_gizmos = { version = "0.17.0", default-features = false }
|
||||
bevy_camera = { version = "0.17.0", default-features = false }
|
||||
bevy_color = { version = "0.17.0", default-features = false }
|
||||
bevy_transform = { version = "0.17.0", default-features = false }
|
||||
bevy_derive = { version = "0.17.0", default-features = false }
|
||||
bevy_platform = { version = "0.17.0", default-features = false }
|
||||
bevy_mod_xr = { path = "crates/bevy_xr", version = "0.3.0" }
|
||||
bevy_mod_openxr = { path = "crates/bevy_openxr", version = "0.3.0" }
|
||||
bevy_xr_utils = { path = "crates/bevy_xr_utils", version = "0.3.0" }
|
||||
openxr = "0.19.0"
|
||||
bevy = { version = "0.18", features = ["debug"] }
|
||||
bevy_ecs = { version = "0.18", default-features = false }
|
||||
bevy_math = { version = "0.18", default-features = false }
|
||||
bevy_render = { version = "0.18", default-features = false }
|
||||
bevy_core_pipeline = { version = "0.18", default-features = false }
|
||||
bevy_window = { version = "0.18", default-features = false }
|
||||
bevy_winit = { version = "0.18", default-features = false }
|
||||
bevy_pbr = { version = "0.18", default-features = false }
|
||||
bevy_app = { version = "0.18", default-features = false }
|
||||
bevy_reflect = { version = "0.18", default-features = false }
|
||||
bevy_log = { version = "0.18", default-features = false }
|
||||
bevy_gizmos = { version = "0.18", default-features = false }
|
||||
bevy_camera = { version = "0.18", default-features = false }
|
||||
bevy_color = { version = "0.18", default-features = false }
|
||||
bevy_transform = { version = "0.18", default-features = false }
|
||||
bevy_derive = { version = "0.18", default-features = false }
|
||||
bevy_platform = { version = "0.18", default-features = false }
|
||||
|
||||
|
||||
bevy_mod_xr = { path = "crates/bevy_xr", version = "0.5.0" }
|
||||
bevy_mod_openxr = { path = "crates/bevy_openxr", version = "0.5.0" }
|
||||
bevy_xr_utils = { path = "crates/bevy_xr_utils", version = "0.5.0" }
|
||||
openxr = "0.21.1"
|
||||
thiserror = "2.0.3"
|
||||
wgpu = "26"
|
||||
wgpu-hal = "26"
|
||||
wgpu = "27"
|
||||
wgpu-hal = "27"
|
||||
|
||||
# Enable a small amount of optimization in the dev profile.
|
||||
[profile.dev]
|
||||
|
||||
@@ -19,7 +19,7 @@ fn main() {
|
||||
.add_plugins(bevy_mod_openxr::features::fb_passthrough::OxrFbPassthroughPlugin)
|
||||
.add_systems(Startup, setup)
|
||||
.add_systems(Update, modify_camera)
|
||||
.insert_resource(AmbientLight {
|
||||
.insert_resource(GlobalAmbientLight {
|
||||
color: Default::default(),
|
||||
brightness: 500.0,
|
||||
affects_lightmapped_meshes: false,
|
||||
|
||||
@@ -119,7 +119,7 @@ fn spawn_hands(
|
||||
actions
|
||||
.left
|
||||
.create_space(
|
||||
session.deref().deref().clone(),
|
||||
session.deref().deref(),
|
||||
openxr::Path::NULL,
|
||||
Posef::IDENTITY,
|
||||
)
|
||||
|
||||
@@ -10,7 +10,7 @@ fn main() -> AppExit {
|
||||
.add_plugins(bevy_mod_xr::hand_debug_gizmos::HandGizmosPlugin)
|
||||
.add_systems(Startup, setup)
|
||||
.add_systems(Update, handle_input)
|
||||
.insert_resource(AmbientLight::default())
|
||||
.insert_resource(GlobalAmbientLight::default())
|
||||
.run()
|
||||
}
|
||||
|
||||
|
||||
@@ -2,3 +2,15 @@
|
||||
mod openxr;
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
pub use openxr::*;
|
||||
|
||||
pub mod prelude {
|
||||
pub use crate::{
|
||||
action_binding::OxrSendActionBindings, action_binding::OxrSuggestActionBinding,
|
||||
action_set_attaching::OxrAttachActionSet, action_set_syncing::OxrActionSetSyncSet,
|
||||
action_set_syncing::OxrSyncActionSet, add_xr_plugins, exts::OxrExtensions,
|
||||
features::handtracking::HandTrackingPlugin, init::OxrInitPlugin, openxr_session_running,
|
||||
resources::OxrInstance, resources::OxrSessionConfig, session::OxrSession,
|
||||
spaces::OxrSpaceExt,
|
||||
};
|
||||
pub use openxr::EnvironmentBlendMode;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
use std::{
|
||||
ffi::CStr,
|
||||
ops::{BitAnd, BitOr},
|
||||
};
|
||||
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::resource::Resource;
|
||||
use bevy_log::error;
|
||||
use openxr::ExtensionSet;
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Deref, DerefMut, Resource)]
|
||||
@@ -36,7 +42,41 @@ impl OxrExtensions {
|
||||
}
|
||||
/// returns true if all of the extensions enabled are also available in `available_exts`
|
||||
pub fn is_available(&self, available_exts: &OxrExtensions) -> bool {
|
||||
self.clone() & available_exts.clone() == *self
|
||||
self.0.intersection(available_exts) == self.0
|
||||
}
|
||||
/// Returns any extensions needed by `required_exts` that aren't available in `self`
|
||||
pub fn unavailable_exts(&self, required_exts: &Self) -> Vec<String> {
|
||||
required_exts
|
||||
.difference(self)
|
||||
.names()
|
||||
.into_iter()
|
||||
.filter_map(|v| {
|
||||
CStr::from_bytes_with_nul(v)
|
||||
.inspect_err(|err| error!("failed to convert openxr ext name to CStr: {err}"))
|
||||
.ok()
|
||||
})
|
||||
.filter_map(|v| {
|
||||
v.to_str()
|
||||
.inspect_err(|err| error!("openxr ext name is not valid utf8: {err}"))
|
||||
.ok()
|
||||
})
|
||||
.map(|v| v.to_string())
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
impl BitOr for OxrExtensions {
|
||||
type Output = Self;
|
||||
|
||||
// this is horribly slow, but doesn't require a bunch of code duplication
|
||||
fn bitor(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0.names().into_iter().chain(rhs.names()).collect())
|
||||
}
|
||||
}
|
||||
impl BitAnd for OxrExtensions {
|
||||
type Output = Self;
|
||||
|
||||
fn bitand(self, rhs: Self) -> Self::Output {
|
||||
Self(self.intersection(&rhs))
|
||||
}
|
||||
}
|
||||
impl From<ExtensionSet> for OxrExtensions {
|
||||
@@ -56,293 +96,3 @@ impl Default for OxrExtensions {
|
||||
Self(exts)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! unavailable_exts {
|
||||
(
|
||||
$exts:ty;
|
||||
$(
|
||||
$(
|
||||
#[$meta:meta]
|
||||
)*
|
||||
$ident:ident
|
||||
),*
|
||||
$(,)?
|
||||
) => {
|
||||
impl $exts {
|
||||
/// Returns any extensions needed by `required_exts` that aren't available in `self`
|
||||
pub fn unavailable_exts(&self, required_exts: &Self) -> Vec<std::borrow::Cow<'static, str>> {
|
||||
let mut exts = vec![];
|
||||
$(
|
||||
$(
|
||||
#[$meta]
|
||||
)*
|
||||
if required_exts.0.$ident && !self.0.$ident {
|
||||
exts.push(std::borrow::Cow::Borrowed(stringify!($ident)))
|
||||
}
|
||||
)*
|
||||
for ext in required_exts.0.other.iter() {
|
||||
if !self.0.other.contains(ext) {
|
||||
exts.push(std::borrow::Cow::Owned(ext.clone()))
|
||||
}
|
||||
}
|
||||
exts
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! bitor {
|
||||
(
|
||||
$exts:ty;
|
||||
$(
|
||||
$(
|
||||
#[$meta:meta]
|
||||
)*
|
||||
$ident:ident
|
||||
),*
|
||||
$(,)?
|
||||
) => {
|
||||
impl std::ops::BitOr for $exts {
|
||||
type Output = Self;
|
||||
|
||||
fn bitor(self, rhs: Self) -> Self::Output {
|
||||
let mut out = ExtensionSet::default();
|
||||
$(
|
||||
$(
|
||||
#[$meta]
|
||||
)*
|
||||
{
|
||||
out.$ident = self.0.$ident || rhs.0.$ident;
|
||||
}
|
||||
|
||||
)*
|
||||
out.other = self.0.other;
|
||||
for ext in rhs.0.other {
|
||||
if !out.other.contains(&ext) {
|
||||
out.other.push(ext);
|
||||
}
|
||||
}
|
||||
Self(out)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! bitand {
|
||||
(
|
||||
$exts:ty;
|
||||
$(
|
||||
$(
|
||||
#[$meta:meta]
|
||||
)*
|
||||
$ident:ident
|
||||
),*
|
||||
$(,)?
|
||||
) => {
|
||||
impl std::ops::BitAnd for $exts {
|
||||
type Output = Self;
|
||||
|
||||
fn bitand(self, rhs: Self) -> Self::Output {
|
||||
let mut out = ExtensionSet::default();
|
||||
$(
|
||||
$(
|
||||
#[$meta]
|
||||
)*
|
||||
{
|
||||
out.$ident = self.0.$ident && rhs.0.$ident;
|
||||
}
|
||||
|
||||
)*
|
||||
for ext in self.0.other {
|
||||
if rhs.0.other.contains(&ext) {
|
||||
out.other.push(ext);
|
||||
}
|
||||
}
|
||||
Self(out)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_ext {
|
||||
(
|
||||
$(
|
||||
$macro:ident
|
||||
),*
|
||||
|
||||
) => {
|
||||
$(
|
||||
$macro! {
|
||||
OxrExtensions;
|
||||
almalence_digital_lens_control,
|
||||
bd_controller_interaction,
|
||||
epic_view_configuration_fov,
|
||||
ext_performance_settings,
|
||||
ext_thermal_query,
|
||||
ext_debug_utils,
|
||||
ext_eye_gaze_interaction,
|
||||
ext_view_configuration_depth_range,
|
||||
ext_conformance_automation,
|
||||
ext_hand_tracking,
|
||||
#[cfg(windows)]
|
||||
ext_win32_appcontainer_compatible,
|
||||
ext_dpad_binding,
|
||||
ext_hand_joints_motion_range,
|
||||
ext_samsung_odyssey_controller,
|
||||
ext_hp_mixed_reality_controller,
|
||||
ext_palm_pose,
|
||||
ext_uuid,
|
||||
ext_hand_interaction,
|
||||
ext_active_action_set_priority,
|
||||
ext_local_floor,
|
||||
ext_hand_tracking_data_source,
|
||||
ext_plane_detection,
|
||||
ext_future,
|
||||
ext_user_presence,
|
||||
fb_composition_layer_image_layout,
|
||||
fb_composition_layer_alpha_blend,
|
||||
#[cfg(target_os = "android")]
|
||||
fb_android_surface_swapchain_create,
|
||||
fb_swapchain_update_state,
|
||||
fb_composition_layer_secure_content,
|
||||
fb_body_tracking,
|
||||
fb_display_refresh_rate,
|
||||
fb_color_space,
|
||||
fb_hand_tracking_mesh,
|
||||
fb_hand_tracking_aim,
|
||||
fb_hand_tracking_capsules,
|
||||
fb_spatial_entity,
|
||||
fb_foveation,
|
||||
fb_foveation_configuration,
|
||||
fb_keyboard_tracking,
|
||||
fb_triangle_mesh,
|
||||
fb_passthrough,
|
||||
fb_render_model,
|
||||
fb_spatial_entity_query,
|
||||
fb_spatial_entity_storage,
|
||||
fb_foveation_vulkan,
|
||||
#[cfg(target_os = "android")]
|
||||
fb_swapchain_update_state_android_surface,
|
||||
fb_swapchain_update_state_opengl_es,
|
||||
fb_swapchain_update_state_vulkan,
|
||||
fb_touch_controller_pro,
|
||||
fb_spatial_entity_sharing,
|
||||
fb_space_warp,
|
||||
fb_haptic_amplitude_envelope,
|
||||
fb_scene,
|
||||
fb_scene_capture,
|
||||
fb_spatial_entity_container,
|
||||
fb_face_tracking,
|
||||
fb_eye_tracking_social,
|
||||
fb_passthrough_keyboard_hands,
|
||||
fb_composition_layer_settings,
|
||||
fb_touch_controller_proximity,
|
||||
fb_haptic_pcm,
|
||||
fb_composition_layer_depth_test,
|
||||
fb_spatial_entity_storage_batch,
|
||||
fb_spatial_entity_user,
|
||||
fb_face_tracking2,
|
||||
htc_vive_cosmos_controller_interaction,
|
||||
htc_facial_tracking,
|
||||
htc_vive_focus3_controller_interaction,
|
||||
htc_hand_interaction,
|
||||
htc_vive_wrist_tracker_interaction,
|
||||
htc_passthrough,
|
||||
htc_foveation,
|
||||
htc_anchor,
|
||||
huawei_controller_interaction,
|
||||
#[cfg(target_os = "android")]
|
||||
khr_android_thread_settings,
|
||||
#[cfg(target_os = "android")]
|
||||
khr_android_surface_swapchain,
|
||||
khr_composition_layer_cube,
|
||||
#[cfg(target_os = "android")]
|
||||
khr_android_create_instance,
|
||||
khr_composition_layer_depth,
|
||||
khr_vulkan_swapchain_format_list,
|
||||
khr_composition_layer_cylinder,
|
||||
khr_composition_layer_equirect,
|
||||
khr_opengl_enable,
|
||||
khr_opengl_es_enable,
|
||||
khr_vulkan_enable,
|
||||
#[cfg(windows)]
|
||||
khr_d3d11_enable,
|
||||
#[cfg(windows)]
|
||||
khr_d3d12_enable,
|
||||
khr_visibility_mask,
|
||||
khr_composition_layer_color_scale_bias,
|
||||
#[cfg(windows)]
|
||||
khr_win32_convert_performance_counter_time,
|
||||
khr_convert_timespec_time,
|
||||
khr_loader_init,
|
||||
#[cfg(target_os = "android")]
|
||||
khr_loader_init_android,
|
||||
khr_vulkan_enable2,
|
||||
khr_composition_layer_equirect2,
|
||||
khr_binding_modification,
|
||||
khr_swapchain_usage_input_attachment_bit,
|
||||
khr_locate_spaces,
|
||||
khr_maintenance1,
|
||||
meta_foveation_eye_tracked,
|
||||
meta_local_dimming,
|
||||
meta_passthrough_preferences,
|
||||
meta_virtual_keyboard,
|
||||
meta_vulkan_swapchain_create_info,
|
||||
meta_performance_metrics,
|
||||
meta_headset_id,
|
||||
meta_recommended_layer_resolution,
|
||||
meta_passthrough_color_lut,
|
||||
meta_spatial_entity_mesh,
|
||||
meta_automatic_layer_filter,
|
||||
meta_touch_controller_plus,
|
||||
meta_environment_depth,
|
||||
ml_ml2_controller_interaction,
|
||||
ml_frame_end_info,
|
||||
ml_global_dimmer,
|
||||
ml_compat,
|
||||
ml_marker_understanding,
|
||||
ml_localization_map,
|
||||
ml_user_calibration,
|
||||
mnd_headless,
|
||||
mnd_swapchain_usage_input_attachment_bit,
|
||||
msft_unbounded_reference_space,
|
||||
msft_spatial_anchor,
|
||||
msft_spatial_graph_bridge,
|
||||
msft_hand_interaction,
|
||||
msft_hand_tracking_mesh,
|
||||
msft_secondary_view_configuration,
|
||||
msft_first_person_observer,
|
||||
msft_controller_model,
|
||||
#[cfg(windows)]
|
||||
msft_perception_anchor_interop,
|
||||
#[cfg(windows)]
|
||||
msft_holographic_window_attachment,
|
||||
msft_composition_layer_reprojection,
|
||||
msft_spatial_anchor_persistence,
|
||||
#[cfg(target_os = "android")]
|
||||
oculus_android_session_state_enable,
|
||||
oculus_audio_device_guid,
|
||||
oculus_external_camera,
|
||||
oppo_controller_interaction,
|
||||
qcom_tracking_optimization_settings,
|
||||
ultraleap_hand_tracking_forearm,
|
||||
valve_analog_threshold,
|
||||
varjo_quad_views,
|
||||
varjo_foveated_rendering,
|
||||
varjo_composition_layer_depth_test,
|
||||
varjo_environment_depth_estimation,
|
||||
varjo_marker_tracking,
|
||||
varjo_view_offset,
|
||||
varjo_xr4_controller_interaction,
|
||||
yvr_controller_interaction,
|
||||
extx_overlay,
|
||||
mndx_egl_enable,
|
||||
mndx_force_feedback_curl,
|
||||
htcx_vive_tracker_interaction,
|
||||
}
|
||||
)*
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
impl_ext!(bitor, bitand, unavailable_exts);
|
||||
|
||||
@@ -69,7 +69,7 @@ pub fn insert_passthrough(world: &mut World) {
|
||||
|
||||
pub fn resume_passthrough(
|
||||
passthrough: Res<OxrPassthrough>,
|
||||
passthrough_layer: Res<OxrPassthroughLayer>,
|
||||
passthrough_layer: Res<OxrPassthroughLayerFB>,
|
||||
) {
|
||||
passthrough.start().unwrap();
|
||||
passthrough_layer.resume().unwrap();
|
||||
@@ -77,7 +77,7 @@ pub fn resume_passthrough(
|
||||
|
||||
pub fn pause_passthrough(
|
||||
passthrough: Res<OxrPassthrough>,
|
||||
passthrough_layer: Res<OxrPassthroughLayer>,
|
||||
passthrough_layer: Res<OxrPassthroughLayerFB>,
|
||||
) {
|
||||
passthrough_layer.pause().unwrap();
|
||||
passthrough.pause().unwrap();
|
||||
@@ -87,7 +87,7 @@ pub fn create_passthrough(
|
||||
session: &OxrSession,
|
||||
flags: openxr::PassthroughFlagsFB,
|
||||
purpose: openxr::PassthroughLayerPurposeFB,
|
||||
) -> OxrResult<(OxrPassthrough, OxrPassthroughLayer)> {
|
||||
) -> OxrResult<(OxrPassthrough, OxrPassthroughLayerFB)> {
|
||||
let passthrough = session.create_passthrough(flags)?;
|
||||
|
||||
let passthrough_layer = session.create_passthrough_layer(&passthrough, purpose)?;
|
||||
|
||||
@@ -14,6 +14,7 @@ use crate::{
|
||||
types::{AppInfo, OxrExtensions, Result, WgpuGraphics},
|
||||
};
|
||||
|
||||
#[allow(clippy::missing_safety_doc)]
|
||||
/// This is an extension trait to the [`Graphics`](openxr::Graphics) trait and is how the graphics API should be interacted with.
|
||||
pub unsafe trait GraphicsExt: openxr::Graphics {
|
||||
/// Wrap the graphics specific type into the [GraphicsWrap] enum
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
use std::ffi::{c_void, CStr, CString};
|
||||
use std::ffi::{CStr, CString, c_void};
|
||||
use std::str::FromStr;
|
||||
|
||||
use ash::vk::{self, Handle};
|
||||
use bevy_log::{debug, error};
|
||||
use bevy_math::UVec2;
|
||||
use openxr::{sys, Version};
|
||||
use wgpu::{InstanceFlags, MemoryBudgetThresholds};
|
||||
use openxr::sys::Handle as _;
|
||||
use openxr::{Version, sys};
|
||||
use wgpu::TextureUses;
|
||||
use wgpu_hal::api::Vulkan;
|
||||
use wgpu::{ExperimentalFeatures, InstanceFlags, MemoryBudgetThresholds};
|
||||
use wgpu_hal::Api;
|
||||
use wgpu_hal::api::Vulkan;
|
||||
|
||||
use super::{GraphicsExt, GraphicsType, GraphicsWrap, OxrManualGraphicsConfig};
|
||||
use crate::error::OxrError;
|
||||
@@ -54,14 +55,13 @@ unsafe impl GraphicsExt for openxr::Vulkan {
|
||||
) -> Result<wgpu::Texture> {
|
||||
let color_image = vk::Image::from_raw(color_image);
|
||||
let wgpu_hal_texture = unsafe {
|
||||
let hal_dev =
|
||||
device
|
||||
.as_hal::<wgpu_hal::vulkan::Api>()
|
||||
.ok_or(OxrError::GraphicsBackendMismatch {
|
||||
item: "Wgpu Device",
|
||||
backend: "unknown",
|
||||
expected_backend: "vulkan",
|
||||
})?;
|
||||
let hal_dev = device.as_hal::<wgpu_hal::vulkan::Api>().ok_or(
|
||||
OxrError::GraphicsBackendMismatch {
|
||||
item: "Wgpu Device",
|
||||
backend: "unknown",
|
||||
expected_backend: "vulkan",
|
||||
},
|
||||
)?;
|
||||
hal_dev.texture_from_raw(
|
||||
color_image,
|
||||
&wgpu_hal::TextureDescriptor {
|
||||
@@ -207,16 +207,8 @@ unsafe impl GraphicsExt for openxr::Vulkan {
|
||||
system_id,
|
||||
};
|
||||
let mut out = sys::Session::NULL;
|
||||
cvt(unsafe { (instance.fp().create_session)(
|
||||
instance.as_raw(),
|
||||
&info,
|
||||
&mut out,
|
||||
) })?;
|
||||
Ok(unsafe { openxr::Session::from_raw(
|
||||
instance.clone(),
|
||||
out,
|
||||
Box::new(()),
|
||||
) })
|
||||
cvt(unsafe { (instance.fp().create_session)(instance.as_raw(), &info, &mut out) })?;
|
||||
Ok(unsafe { openxr::Session::from_raw(instance.clone(), out, Box::new(())) })
|
||||
}
|
||||
|
||||
fn init_fallback_graphics(
|
||||
@@ -300,6 +292,7 @@ fn get_extensions(
|
||||
instance_exts.extend(&cfg.vk_instance_exts);
|
||||
device_exts.extend(&cfg.vk_device_exts);
|
||||
}
|
||||
|
||||
instance_exts.dedup();
|
||||
device_exts.dedup();
|
||||
|
||||
@@ -392,12 +385,13 @@ fn init_from_instance_and_dev(
|
||||
let wgpu_features = wgpu_exposed_adapter.features;
|
||||
debug!("wgpu features: {wgpu_features:#?}");
|
||||
|
||||
let enabled_extensions = wgpu_exposed_adapter
|
||||
let mut enabled_extensions = wgpu_exposed_adapter
|
||||
.adapter
|
||||
.required_device_extensions(wgpu_features);
|
||||
enabled_extensions.extend(device_exts);
|
||||
enabled_extensions.dedup();
|
||||
|
||||
let (wgpu_open_device, vk_device_ptr, queue_family_index) = {
|
||||
let extensions_cchar: Vec<_> = device_exts.iter().map(|s| s.as_ptr()).collect();
|
||||
let mut enabled_phd_features = wgpu_exposed_adapter
|
||||
.adapter
|
||||
.physical_device_features(&enabled_extensions, wgpu_features);
|
||||
@@ -406,17 +400,13 @@ fn init_from_instance_and_dev(
|
||||
.queue_family_index(family_index)
|
||||
.queue_priorities(&[1.0]);
|
||||
let family_infos = [family_info];
|
||||
let mut physical_device_multiview_features = vk::PhysicalDeviceMultiviewFeatures {
|
||||
multiview: vk::TRUE,
|
||||
..Default::default()
|
||||
};
|
||||
let ext_names = enabled_extensions
|
||||
.iter()
|
||||
.map(|e| e.as_ptr())
|
||||
.collect::<Vec<_>>();
|
||||
let info = enabled_phd_features
|
||||
.add_to_device_create(
|
||||
vk::DeviceCreateInfo::default()
|
||||
.queue_create_infos(&family_infos)
|
||||
.push_next(&mut physical_device_multiview_features),
|
||||
)
|
||||
.enabled_extension_names(&extensions_cchar);
|
||||
.add_to_device_create(vk::DeviceCreateInfo::default().queue_create_infos(&family_infos))
|
||||
.enabled_extension_names(&ext_names);
|
||||
let vk_device = create_dev(&info)?;
|
||||
let vk_device_ptr = vk_device.handle().as_raw() as *const c_void;
|
||||
|
||||
@@ -453,6 +443,7 @@ fn init_from_instance_and_dev(
|
||||
required_limits: limits,
|
||||
memory_hints: wgpu::MemoryHints::Performance,
|
||||
trace: wgpu::Trace::Off,
|
||||
experimental_features: ExperimentalFeatures::enabled(),
|
||||
},
|
||||
)
|
||||
}?;
|
||||
@@ -475,11 +466,7 @@ fn init_from_instance_and_dev(
|
||||
}
|
||||
|
||||
fn cvt(x: sys::Result) -> openxr::Result<sys::Result> {
|
||||
if x.into_raw() >= 0 {
|
||||
Ok(x)
|
||||
} else {
|
||||
Err(x)
|
||||
}
|
||||
if x.into_raw() >= 0 { Ok(x) } else { Err(x) }
|
||||
}
|
||||
|
||||
fn vulkan_to_wgpu(format: vk::Format) -> Option<wgpu::TextureFormat> {
|
||||
@@ -811,6 +798,7 @@ fn wgpu_to_vulkan(format: wgpu::TextureFormat) -> Option<vk::Format> {
|
||||
Tf::EacR11Snorm => F::EAC_R11_SNORM_BLOCK,
|
||||
Tf::EacRg11Unorm => F::EAC_R11G11_UNORM_BLOCK,
|
||||
Tf::EacRg11Snorm => F::EAC_R11G11_SNORM_BLOCK,
|
||||
Tf::P010 => F::G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16,
|
||||
Tf::Astc { block, channel } => match channel {
|
||||
AstcChannel::Unorm => match block {
|
||||
AstcBlock::B4x4 => F::ASTC_4X4_UNORM_BLOCK,
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::mem;
|
||||
|
||||
use bevy_ecs::world::World;
|
||||
use bevy_mod_xr::spaces::{XrPrimaryReferenceSpace, XrSpace};
|
||||
use openxr::{sys, CompositionLayerFlags, Fovf, Posef, Rect2Di};
|
||||
use openxr::{CompositionLayerFlags, Fovf, Posef, Rect2Di, sys};
|
||||
|
||||
use crate::graphics::graphics_match;
|
||||
use crate::resources::*;
|
||||
@@ -65,8 +65,8 @@ impl LayerProvider for ProjectionLayer {
|
||||
impl LayerProvider for PassthroughLayer {
|
||||
fn get(&self, world: &World) -> Option<Box<dyn CompositionLayer<'_>>> {
|
||||
Some(Box::new(
|
||||
CompositionLayerPassthrough::new()
|
||||
.layer_handle(world.get_resource::<OxrPassthroughLayer>()?)
|
||||
CompositionLayerPassthroughFB::new()
|
||||
.layer_handle(world.get_resource::<OxrPassthroughLayerFB>()?)
|
||||
.layer_flags(CompositionLayerFlags::BLEND_TEXTURE_SOURCE_ALPHA),
|
||||
))
|
||||
}
|
||||
@@ -236,16 +236,16 @@ impl Default for CompositionLayerProjection<'_> {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
pub struct CompositionLayerPassthrough {
|
||||
pub struct CompositionLayerPassthroughFB {
|
||||
inner: sys::CompositionLayerPassthroughFB,
|
||||
}
|
||||
impl Default for CompositionLayerPassthrough {
|
||||
impl Default for CompositionLayerPassthroughFB {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl CompositionLayerPassthrough {
|
||||
impl CompositionLayerPassthroughFB {
|
||||
#[inline]
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
@@ -256,7 +256,7 @@ impl CompositionLayerPassthrough {
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn layer_handle(mut self, layer_handle: &OxrPassthroughLayer) -> Self {
|
||||
pub fn layer_handle(mut self, layer_handle: &OxrPassthroughLayerFB) -> Self {
|
||||
self.inner.layer_handle = *layer_handle.inner();
|
||||
self
|
||||
}
|
||||
@@ -266,7 +266,7 @@ impl CompositionLayerPassthrough {
|
||||
self
|
||||
}
|
||||
}
|
||||
unsafe impl<'a> CompositionLayer<'a> for CompositionLayerPassthrough {
|
||||
unsafe impl<'a> CompositionLayer<'a> for CompositionLayerPassthroughFB {
|
||||
fn swapchain(&self) -> Option<&'a OxrSwapchain> {
|
||||
None
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ pub struct OxrReferenceSpacePlugin {
|
||||
impl Default for OxrReferenceSpacePlugin {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
default_primary_ref_space: openxr::ReferenceSpaceType::STAGE,
|
||||
default_primary_ref_space: openxr::ReferenceSpaceType::LOCAL,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,24 +7,24 @@ use bevy_ecs::{
|
||||
system::{Commands, Query, Res, ResMut},
|
||||
world::World,
|
||||
};
|
||||
use bevy_log::{debug_span, error, info};
|
||||
use bevy_log::{debug_span, error, info, warn};
|
||||
use bevy_render::{
|
||||
Render, RenderApp,
|
||||
extract_resource::ExtractResourcePlugin,
|
||||
pipelined_rendering::PipelinedRenderingPlugin,
|
||||
texture::{ManualTextureView, ManualTextureViews},
|
||||
view::ExtractedView,
|
||||
Render, RenderApp,
|
||||
};
|
||||
|
||||
use bevy_mod_xr::{
|
||||
camera::{calculate_projection, Fov, XrCamera, XrProjection, XrViewInit},
|
||||
camera::{Fov, XrCamera, XrProjection, XrViewInit, calculate_projection},
|
||||
session::{
|
||||
XrFirst, XrHandleEvents, XrPreDestroySession, XrRenderSystems, XrRootTransform,
|
||||
XrSessionCreated,
|
||||
},
|
||||
spaces::XrPrimaryReferenceSpace,
|
||||
};
|
||||
use bevy_transform::{components::Transform, TransformSystems};
|
||||
use bevy_transform::{TransformSystems, components::Transform};
|
||||
use openxr::ViewStateFlags;
|
||||
|
||||
use crate::{helper_traits::ToTransform as _, init::should_run_frame_loop, resources::*};
|
||||
@@ -158,10 +158,7 @@ pub fn init_views<const SPAWN_CAMERAS: bool>(
|
||||
add_texture_view(&mut manual_texture_views, temp_tex, &graphics_info, index);
|
||||
if SPAWN_CAMERAS {
|
||||
commands.spawn((
|
||||
Camera {
|
||||
target: RenderTarget::TextureView(view_handle),
|
||||
..Default::default()
|
||||
},
|
||||
RenderTarget::TextureView(view_handle),
|
||||
XrCamera(index),
|
||||
Projection::custom(XrProjection::default()),
|
||||
// NoFrustumCulling,
|
||||
@@ -177,14 +174,14 @@ pub fn wait_frame(mut frame_waiter: ResMut<OxrFrameWaiter>, mut commands: Comman
|
||||
|
||||
pub fn update_cameras(
|
||||
frame_state: Res<OxrFrameState>,
|
||||
mut cameras: Query<(&mut Camera, &XrCamera)>,
|
||||
mut cameras: Query<(&mut Camera, &mut RenderTarget, &XrCamera)>,
|
||||
) {
|
||||
for (mut camera, xr_camera) in &mut cameras {
|
||||
camera.target =
|
||||
for (_, mut target, xr_camera) in &mut cameras {
|
||||
*target =
|
||||
RenderTarget::TextureView(ManualTextureViewHandle(XR_TEXTURE_INDEX + xr_camera.0));
|
||||
}
|
||||
if frame_state.is_changed() {
|
||||
for (mut camera, _) in &mut cameras {
|
||||
for (mut camera, _, _) in &mut cameras {
|
||||
camera.is_active = frame_state.should_render
|
||||
}
|
||||
}
|
||||
@@ -205,13 +202,16 @@ pub fn locate_views(
|
||||
} else {
|
||||
frame_state.predicted_display_time
|
||||
};
|
||||
let (flags, xr_views) = session
|
||||
let Ok((flags, xr_views)) = session
|
||||
.locate_views(
|
||||
openxr::ViewConfigurationType::PRIMARY_STEREO,
|
||||
time,
|
||||
&ref_space,
|
||||
)
|
||||
.expect("Failed to locate views");
|
||||
.inspect_err(|err| warn!("failed to locate views: {err}"))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
match (
|
||||
flags & ViewStateFlags::ORIENTATION_VALID == ViewStateFlags::ORIENTATION_VALID,
|
||||
@@ -286,7 +286,11 @@ pub fn insert_texture_views(
|
||||
mut swapchain: ResMut<OxrSwapchain>,
|
||||
mut manual_texture_views: ResMut<ManualTextureViews>,
|
||||
graphics_info: Res<OxrCurrentSessionConfig>,
|
||||
frame_state: Res<OxrFrameState>,
|
||||
) {
|
||||
if !frame_state.should_render {
|
||||
return;
|
||||
}
|
||||
let index = swapchain.acquire_image().expect("Failed to acquire image");
|
||||
let image = &swapchain_images[index as usize];
|
||||
|
||||
@@ -296,10 +300,12 @@ pub fn insert_texture_views(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wait_image(mut swapchain: ResMut<OxrSwapchain>) {
|
||||
swapchain
|
||||
.wait_image(openxr::Duration::INFINITE)
|
||||
.expect("Failed to wait image");
|
||||
pub fn wait_image(mut swapchain: ResMut<OxrSwapchain>, state: Res<OxrFrameState>) {
|
||||
if state.should_render {
|
||||
swapchain
|
||||
.wait_image(openxr::Duration::INFINITE)
|
||||
.expect("Failed to wait image");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_texture_view(
|
||||
@@ -317,7 +323,7 @@ pub fn add_texture_view(
|
||||
let view = ManualTextureView {
|
||||
texture_view: view.into(),
|
||||
size: info.resolution,
|
||||
format: info.format,
|
||||
view_format: info.format,
|
||||
};
|
||||
let handle = ManualTextureViewHandle(XR_TEXTURE_INDEX + index);
|
||||
manual_texture_views.insert(handle, view);
|
||||
@@ -328,7 +334,10 @@ pub fn begin_frame(mut frame_stream: ResMut<OxrFrameStream>) {
|
||||
frame_stream.begin().expect("Failed to begin frame");
|
||||
}
|
||||
|
||||
pub fn release_image(mut swapchain: ResMut<OxrSwapchain>) {
|
||||
pub fn release_image(mut swapchain: ResMut<OxrSwapchain>, state: Res<OxrFrameState>) {
|
||||
if !state.should_render {
|
||||
return;
|
||||
}
|
||||
#[cfg(target_os = "android")]
|
||||
{
|
||||
let ctx = ndk_context::android_context();
|
||||
|
||||
@@ -47,7 +47,7 @@ impl OxrEntry {
|
||||
application_version: app_info.version.to_u32(),
|
||||
engine_name: "Bevy",
|
||||
engine_version: Version::BEVY.to_u32(),
|
||||
api_version: openxr::Version::new(1, 0, 34),
|
||||
api_version: openxr::Version::new(1, 1, 54),
|
||||
},
|
||||
&required_exts.into(),
|
||||
layers,
|
||||
@@ -322,11 +322,11 @@ impl OxrPassthrough {
|
||||
|
||||
/// Wrapper around [`openxr::Passthrough`].
|
||||
///
|
||||
/// Used to create a [`CompositionLayerPassthrough`](crate::layer_builder::CompositionLayerPassthrough), and to [`pause`](openxr::PassthroughLayer::pause) or [`resume`](openxr::PassthroughLayer::resume) rendering of the passthrough layer.
|
||||
/// Used to create a [`CompositionLayerPassthrough`](crate::layer_builder::CompositionLayerPassthrough), and to [`pause`](openxr::PassthroughLayerFB::pause) or [`resume`](openxr::PassthroughLayerFB::resume) rendering of the passthrough layer.
|
||||
///
|
||||
/// See [`openxr::PassthroughLayer`] for available methods.
|
||||
/// See [`openxr::PassthroughLayerFB`] for available methods.
|
||||
#[derive(Resource, Deref, DerefMut)]
|
||||
pub struct OxrPassthroughLayer(pub openxr::PassthroughLayer);
|
||||
pub struct OxrPassthroughLayerFB(pub openxr::PassthroughLayerFB);
|
||||
|
||||
#[derive(Resource, Deref, DerefMut, Default)]
|
||||
pub struct OxrRenderLayers(pub Vec<Box<dyn LayerProvider + Send + Sync>>);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::ffi::c_void;
|
||||
|
||||
use crate::next_chain::{OxrNextChain, OxrNextChainStructBase, OxrNextChainStructProvider};
|
||||
use crate::resources::{OxrPassthrough, OxrPassthroughLayer, OxrSwapchain};
|
||||
use crate::resources::{OxrPassthrough, OxrPassthroughLayerFB, OxrSwapchain};
|
||||
use crate::types::{Result, SwapchainCreateInfo};
|
||||
use bevy_derive::Deref;
|
||||
use bevy_ecs::resource::Resource;
|
||||
@@ -91,8 +91,8 @@ impl OxrSession {
|
||||
&self,
|
||||
passthrough: &OxrPassthrough,
|
||||
purpose: openxr::PassthroughLayerPurposeFB,
|
||||
) -> Result<OxrPassthroughLayer> {
|
||||
Ok(OxrPassthroughLayer(graphics_match! {
|
||||
) -> Result<OxrPassthroughLayerFB> {
|
||||
Ok(OxrPassthroughLayerFB(graphics_match! {
|
||||
&self.1;
|
||||
session => session.create_passthrough_layer(&passthrough.0, passthrough.1, purpose)?
|
||||
}))
|
||||
|
||||
@@ -19,7 +19,7 @@ use bevy_platform::collections::hash_set::HashSet;
|
||||
use bevy_transform::components::Transform;
|
||||
use openxr::{
|
||||
HAND_JOINT_COUNT, HandJointLocation, HandJointLocations, HandJointVelocities,
|
||||
HandJointVelocity, ReferenceSpaceType, SpaceLocationFlags, SpaceVelocityFlags, sys,
|
||||
HandJointVelocity, ReferenceSpaceType, SpaceLocationFlags, SpaceVelocityFlags, sys::{self, Handle as _},
|
||||
};
|
||||
use std::{mem::MaybeUninit, ptr, sync::Mutex};
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ fn on_tracker_add(mut world: DeferredWorld, HookContext { entity, .. }: HookCont
|
||||
if world
|
||||
.entity(entity)
|
||||
.get_components::<Has<Children>>()
|
||||
.is_some_and(identity)
|
||||
.is_ok_and(identity)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ bevy.workspace = true
|
||||
|
||||
[target.'cfg(not(target_family = "wasm"))'.dependencies]
|
||||
openxr.workspace = true
|
||||
openxr_mndx_xdev_space = "0.1.0"
|
||||
openxr_mndx_xdev_space = "0.2.0"
|
||||
|
||||
[lints.clippy]
|
||||
too_many_arguments = "allow"
|
||||
|
||||
@@ -19,9 +19,9 @@ fn main() {
|
||||
.add_systems(Update, read_action_with_marker_component)
|
||||
.add_systems(Update, handle_flight_input)
|
||||
// Realtime lighting is expensive, use ambient light instead
|
||||
.insert_resource(AmbientLight {
|
||||
.insert_resource(GlobalAmbientLight {
|
||||
brightness: 500.0,
|
||||
..AmbientLight::default()
|
||||
..GlobalAmbientLight::default()
|
||||
})
|
||||
.run();
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ fn main() -> AppExit {
|
||||
exts: {
|
||||
let mut exts = OxrExtensions::default();
|
||||
exts.enable_hand_tracking();
|
||||
exts.other.push("XR_MNDX_xdev_space".to_string());
|
||||
exts.other.push(c"XR_MNDX_xdev_space".to_bytes_with_nul().to_vec());
|
||||
exts
|
||||
},
|
||||
..Default::default()
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
use bevy::prelude::*;
|
||||
use bevy_mod_openxr::add_xr_plugins;
|
||||
use bevy_xr_utils::transform_utils::{self, SnapToPosition, SnapToRotation};
|
||||
use bevy_xr_utils::xr_utils_actions::{
|
||||
ActiveSet, XRUtilsAction, XRUtilsActionSet, XRUtilsActionState, XRUtilsActionSystems,
|
||||
XRUtilsActionsPlugin, XRUtilsBinding,
|
||||
use bevy_xr_utils::actions::{
|
||||
ActionType, ActiveSet, XRUtilsAction, XRUtilsActionSet, XRUtilsActionState, XRUtilsActionSystems, XRUtilsActionsPlugin, XRUtilsBinding
|
||||
};
|
||||
|
||||
fn main() -> AppExit {
|
||||
@@ -27,9 +26,9 @@ fn main() -> AppExit {
|
||||
Update,
|
||||
send_recenter.after(XRUtilsActionSystems::SyncActionStates),
|
||||
)
|
||||
.insert_resource(AmbientLight {
|
||||
.insert_resource(GlobalAmbientLight {
|
||||
brightness: 500.0,
|
||||
..AmbientLight::default()
|
||||
..GlobalAmbientLight::default()
|
||||
})
|
||||
.run()
|
||||
}
|
||||
@@ -104,7 +103,7 @@ fn create_action_entities(mut commands: Commands) {
|
||||
XRUtilsAction {
|
||||
action_name: "face_red".into(),
|
||||
localized_name: "face_red_localized".into(),
|
||||
action_type: bevy_mod_xr::actions::ActionType::Bool,
|
||||
action_type: ActionType::Bool,
|
||||
},
|
||||
FaceRedAction, //lets try a marker component
|
||||
))
|
||||
@@ -128,7 +127,7 @@ fn create_action_entities(mut commands: Commands) {
|
||||
XRUtilsAction {
|
||||
action_name: "center".into(),
|
||||
localized_name: "center_localized".into(),
|
||||
action_type: bevy_mod_xr::actions::ActionType::Bool,
|
||||
action_type: ActionType::Bool,
|
||||
},
|
||||
Center, //lets try a marker component
|
||||
))
|
||||
@@ -150,7 +149,7 @@ fn create_action_entities(mut commands: Commands) {
|
||||
|
||||
fn send_look_at_red_cube_event(
|
||||
mut action_query: Query<&XRUtilsActionState, With<FaceRedAction>>,
|
||||
mut event_writer: EventWriter<SnapToRotation>,
|
||||
mut event_writer: MessageWriter<SnapToRotation>,
|
||||
) {
|
||||
//now for the actual checking
|
||||
for state in action_query.iter_mut() {
|
||||
@@ -175,7 +174,7 @@ pub struct Center;
|
||||
|
||||
fn send_recenter(
|
||||
mut action_query: Query<&XRUtilsActionState, With<Center>>,
|
||||
mut event_writer: EventWriter<SnapToPosition>,
|
||||
mut event_writer: MessageWriter<SnapToPosition>,
|
||||
) {
|
||||
//now for the actual checking
|
||||
for state in action_query.iter_mut() {
|
||||
|
||||
Reference in New Issue
Block a user