rendering code and api crate

This commit is contained in:
awtterpip
2024-03-10 19:59:19 -05:00
parent 47eba9215f
commit 91eb263b4f
31 changed files with 1597 additions and 1775 deletions

View File

@@ -0,0 +1,9 @@
[package]
name = "bevy_xr"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
bevy.workspace = true

View File

@@ -0,0 +1,102 @@
use bevy::app::{App, Plugin};
use bevy::core_pipeline::core_3d::graph::Core3d;
use bevy::core_pipeline::core_3d::Camera3d;
use bevy::core_pipeline::tonemapping::{DebandDither, Tonemapping};
use bevy::ecs::bundle::Bundle;
use bevy::ecs::component::Component;
use bevy::ecs::reflect::ReflectComponent;
use bevy::math::{Mat4, Vec3A};
use bevy::reflect::Reflect;
use bevy::render::camera::{
Camera, CameraMainTextureUsages, CameraProjection, CameraProjectionPlugin, CameraRenderGraph,
Exposure,
};
use bevy::render::primitives::Frustum;
use bevy::render::view::{ColorGrading, VisibleEntities};
use bevy::transform::components::{GlobalTransform, Transform};
pub struct XrCameraPlugin;
impl Plugin for XrCameraPlugin {
fn build(&self, app: &mut App) {
app.add_plugins(CameraProjectionPlugin::<XrProjection>::default());
}
}
#[derive(Clone, Copy, Component, Reflect, Debug)]
#[reflect(Component)]
pub struct XrProjection {
pub projection_matrix: Mat4,
pub near: f32,
pub far: f32,
}
impl Default for XrProjection {
fn default() -> Self {
Self {
near: 0.1,
far: 1000.,
projection_matrix: Mat4::IDENTITY,
}
}
}
/// Marker component for an XR view. It is the backends responsibility to update this.
#[derive(Clone, Copy, Component, Debug, Default)]
pub struct XrView;
impl CameraProjection for XrProjection {
fn get_projection_matrix(&self) -> Mat4 {
self.projection_matrix
}
fn update(&mut self, _width: f32, _height: f32) {}
fn far(&self) -> f32 {
self.far
}
// TODO calculate this properly
fn get_frustum_corners(&self, _z_near: f32, _z_far: f32) -> [Vec3A; 8] {
Default::default()
}
}
#[derive(Bundle)]
pub struct XrCameraBundle {
pub camera: Camera,
pub camera_render_graph: CameraRenderGraph,
pub projection: XrProjection,
pub visible_entities: VisibleEntities,
pub frustum: Frustum,
pub transform: Transform,
pub global_transform: GlobalTransform,
pub camera_3d: Camera3d,
pub tonemapping: Tonemapping,
pub dither: DebandDither,
pub color_grading: ColorGrading,
pub exposure: Exposure,
pub main_texture_usages: CameraMainTextureUsages,
pub view: XrView,
}
impl Default for XrCameraBundle {
fn default() -> Self {
Self {
camera_render_graph: CameraRenderGraph::new(Core3d),
camera: Default::default(),
projection: Default::default(),
visible_entities: Default::default(),
frustum: Default::default(),
transform: Default::default(),
global_transform: Default::default(),
camera_3d: Default::default(),
tonemapping: Default::default(),
color_grading: Default::default(),
exposure: Default::default(),
main_texture_usages: Default::default(),
dither: DebandDither::Enabled,
view: XrView,
}
}
}

View File

@@ -0,0 +1,2 @@
pub mod camera;
pub mod session;

View File

@@ -0,0 +1,89 @@
use bevy::app::{App, Plugin, PreUpdate};
use bevy::ecs::event::{Event, EventReader, EventWriter};
use bevy::ecs::system::Local;
pub struct XrSessionPlugin;
impl Plugin for XrSessionPlugin {
fn build(&self, app: &mut App) {
app.add_event::<CreateXrSession>()
.add_event::<BeginXrSession>()
.add_event::<EndXrSession>()
.add_event::<XrSessionState>()
.add_event::<XrInstanceCreated>()
.add_event::<XrInstanceDestroyed>()
.add_systems(PreUpdate, handle_xr_events);
}
}
pub fn handle_xr_events(
mut instance_created: EventReader<XrInstanceCreated>,
mut session_state: EventReader<XrSessionState>,
mut instance_destroyed: EventReader<XrInstanceDestroyed>,
mut create_session: EventWriter<CreateXrSession>,
mut begin_session: EventWriter<BeginXrSession>,
mut has_instance: Local<bool>,
mut local_session_state: Local<Option<XrSessionState>>,
) {
// Don't do anything if no events recieved
if instance_created.is_empty() && instance_destroyed.is_empty() && session_state.is_empty() {
return;
}
if !instance_created.is_empty() {
*has_instance = true;
instance_created.clear();
}
if !instance_destroyed.is_empty() {
*has_instance = false;
instance_destroyed.clear();
}
for state in session_state.read() {
*local_session_state = Some(*state);
}
if *has_instance {
if local_session_state.is_none() {
create_session.send_default();
} else if matches!(*local_session_state, Some(XrSessionState::Ready)) {
begin_session.send_default();
}
}
}
/// Event sent to backends to create an XR session
#[derive(Event, Clone, Copy, Default)]
pub struct CreateXrSession;
/// Event sent to backends to begin an XR session
#[derive(Event, Clone, Copy, Default)]
pub struct BeginXrSession;
/// Event sent to backends to end an XR session.
#[derive(Event, Clone, Copy, Default)]
pub struct EndXrSession;
// /// Event sent to backends to destroy an XR session.
// #[derive(Event, Clone, Copy, Default)]
// pub struct DestroyXrSession;
/// Event sent from backends to inform the frontend of the session state.
#[derive(Event, Clone, Copy)]
pub enum XrSessionState {
/// The session is in an idle state. Either just created or stopped
Idle,
/// The session is ready. You may send a [`BeginXrSession`] event.
Ready,
/// The session is running.
Running,
/// The session is being stopped
Stopping,
/// The session is destroyed
Destroyed,
}
/// Event sent from backends to inform the frontend that the instance was created.
#[derive(Event, Clone, Copy, Default)]
pub struct XrInstanceCreated;
/// Event sent from backends to inform the frontend that the instance was destroyed.
#[derive(Event, Clone, Copy, Default)]
pub struct XrInstanceDestroyed;