refactor: get models fully working
Signed-off-by: Schmarni <marnistromer@gmail.com>
This commit is contained in:
@@ -26,6 +26,14 @@ path = "src/main.rs"
|
|||||||
profile_tokio = ["dep:console-subscriber", "tokio/tracing"]
|
profile_tokio = ["dep:console-subscriber", "tokio/tracing"]
|
||||||
profile_app = ["dep:tracing-tracy"]
|
profile_app = ["dep:tracing-tracy"]
|
||||||
|
|
||||||
|
# Enable a small amount of optimization in the dev profile.
|
||||||
|
[profile.dev]
|
||||||
|
opt-level = 1
|
||||||
|
|
||||||
|
# Enable a large amount of optimization in the dev profile for dependencies.
|
||||||
|
[profile.dev.package."*"]
|
||||||
|
opt-level = 3
|
||||||
|
|
||||||
[package.metadata.appimage]
|
[package.metadata.appimage]
|
||||||
auto_link = true
|
auto_link = true
|
||||||
auto_link_exclude_list = [
|
auto_link_exclude_list = [
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
use bevy::{
|
use bevy::{
|
||||||
app::MainScheduleOrder,
|
app::MainScheduleOrder,
|
||||||
ecs::schedule::{ExecutorKind, ScheduleLabel},
|
ecs::schedule::{ExecutorKind, ScheduleLabel},
|
||||||
@@ -6,13 +8,25 @@ use bevy::{
|
|||||||
};
|
};
|
||||||
use bevy_mod_openxr::session::OxrSession;
|
use bevy_mod_openxr::session::OxrSession;
|
||||||
use bevy_mod_xr::session::{session_available, XrFirst, XrSessionCreated};
|
use bevy_mod_xr::session::{session_available, XrFirst, XrSessionCreated};
|
||||||
|
use once_cell::sync::OnceCell;
|
||||||
use openxr::ReferenceSpaceType;
|
use openxr::ReferenceSpaceType;
|
||||||
use stardust_xr::values::color::{color_space::LinearRgb, AlphaColor, Rgb};
|
use stardust_xr::values::color::{color_space::LinearRgb, AlphaColor, Rgb};
|
||||||
|
|
||||||
use crate::objects::Inputs;
|
|
||||||
|
|
||||||
pub struct StardustBevyPlugin;
|
pub struct StardustBevyPlugin;
|
||||||
|
|
||||||
|
pub static DESTROY_ENTITY: DestroySender = DestroySender(OnceCell::new());
|
||||||
|
|
||||||
|
pub struct DestroySender(OnceCell<crossbeam_channel::Sender<Entity>>);
|
||||||
|
impl Deref for DestroySender {
|
||||||
|
type Target = crossbeam_channel::Sender<Entity>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.0.get().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Resource, Deref)]
|
||||||
|
struct DestroyEntityReader(crossbeam_channel::Receiver<Entity>);
|
||||||
|
|
||||||
#[derive(Resource, Deref)]
|
#[derive(Resource, Deref)]
|
||||||
pub struct DbusConnection(pub zbus::Connection);
|
pub struct DbusConnection(pub zbus::Connection);
|
||||||
|
|
||||||
@@ -22,6 +36,12 @@ pub struct InputUpdate;
|
|||||||
pub struct StardustFirst;
|
pub struct StardustFirst;
|
||||||
impl Plugin for StardustBevyPlugin {
|
impl Plugin for StardustBevyPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
|
let (tx, rx) = crossbeam_channel::unbounded();
|
||||||
|
DESTROY_ENTITY
|
||||||
|
.0
|
||||||
|
.set(tx)
|
||||||
|
.expect("unable to set destroy entity sender, yell at schmarni pls thx");
|
||||||
|
app.insert_resource(DestroyEntityReader(rx));
|
||||||
app.init_schedule(StardustExtract);
|
app.init_schedule(StardustExtract);
|
||||||
let labels = &mut app.world_mut().resource_mut::<MainScheduleOrder>().labels;
|
let labels = &mut app.world_mut().resource_mut::<MainScheduleOrder>().labels;
|
||||||
info!("test: {labels:?}");
|
info!("test: {labels:?}");
|
||||||
@@ -42,9 +62,24 @@ impl Plugin for StardustBevyPlugin {
|
|||||||
panic!("first schedule was not XrFirst!");
|
panic!("first schedule was not XrFirst!");
|
||||||
}
|
}
|
||||||
labels.insert(0, (StardustFirst).intern());
|
labels.insert(0, (StardustFirst).intern());
|
||||||
|
app.add_systems(First, yeet_entities);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn yeet_entities(
|
||||||
|
mut cmds: Commands,
|
||||||
|
query: Query<Entity, With<TemporaryEntity>>,
|
||||||
|
reader: Res<DestroyEntityReader>,
|
||||||
|
) {
|
||||||
|
query
|
||||||
|
.iter()
|
||||||
|
.for_each(|e| cmds.entity(e).despawn_recursive());
|
||||||
|
reader
|
||||||
|
.0
|
||||||
|
.try_iter()
|
||||||
|
.for_each(|e| cmds.entity(e).despawn_recursive());
|
||||||
|
}
|
||||||
|
|
||||||
fn make_view_space(mut cmds: Commands, session: Res<OxrSession>) {
|
fn make_view_space(mut cmds: Commands, session: Res<OxrSession>) {
|
||||||
// idk what errors this function returns
|
// idk what errors this function returns
|
||||||
let view_space = session
|
let view_space = session
|
||||||
@@ -58,17 +93,6 @@ fn make_view_space(mut cmds: Commands, session: Res<OxrSession>) {
|
|||||||
fn spawn_camera(mut cmds: Commands) {
|
fn spawn_camera(mut cmds: Commands) {
|
||||||
cmds.spawn((Camera3d::default(), ViewLocation));
|
cmds.spawn((Camera3d::default(), ViewLocation));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deref, DerefMut, Resource)]
|
|
||||||
pub struct BevyToStardustEvents(pub Vec<BevyToStardustEvent>);
|
|
||||||
pub enum BevyToStardustEvent {
|
|
||||||
InputsCreated(Inputs),
|
|
||||||
SessionDestroyed,
|
|
||||||
SessionEnding,
|
|
||||||
SessionCreated(OxrSession),
|
|
||||||
MainSessionVisible(bool),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait StardustAabb3dExt {
|
pub trait StardustAabb3dExt {
|
||||||
fn grown_box(&self, aabb: &Self, opt_box_transform: Option<impl Into<Mat4>>) -> Self;
|
fn grown_box(&self, aabb: &Self, opt_box_transform: Option<impl Into<Mat4>>) -> Self;
|
||||||
fn grown_point(&self, pt: impl Into<Vec3>) -> Self;
|
fn grown_point(&self, pt: impl Into<Vec3>) -> Self;
|
||||||
|
|||||||
39
src/main.rs
39
src/main.rs
@@ -12,15 +12,16 @@ use crate::core::destroy_queue;
|
|||||||
// use crate::nodes::items::camera;
|
// use crate::nodes::items::camera;
|
||||||
use crate::nodes::{audio, drawable, input};
|
use crate::nodes::{audio, drawable, input};
|
||||||
|
|
||||||
use bevy::app::{App, PluginGroup, PluginsState, Startup, Update};
|
use bevy::app::{App, PluginGroup, PluginsState, PostUpdate, Startup, Update};
|
||||||
use bevy::asset::{AssetServer, Handle};
|
use bevy::asset::{AssetServer, Handle};
|
||||||
|
use bevy::color::Color;
|
||||||
use bevy::core_pipeline::Skybox;
|
use bevy::core_pipeline::Skybox;
|
||||||
use bevy::image::Image;
|
use bevy::image::Image;
|
||||||
use bevy::log::LogPlugin;
|
use bevy::log::LogPlugin;
|
||||||
use bevy::pbr::StandardMaterial;
|
use bevy::pbr::StandardMaterial;
|
||||||
use bevy::prelude::{
|
use bevy::prelude::{
|
||||||
on_event, resource_added, Camera3d, ClearColor, Commands, Entity, EventReader,
|
on_event, resource_added, Camera3d, ClearColor, Commands, Entity, EventReader,
|
||||||
IntoSystemConfigs, Local, Query, Res, Resource, With, World,
|
IntoSystemConfigs, Local, Query, Res, ResMut, Resource, Transform, With, World,
|
||||||
};
|
};
|
||||||
use bevy::render::pipelined_rendering::PipelinedRenderingPlugin;
|
use bevy::render::pipelined_rendering::PipelinedRenderingPlugin;
|
||||||
use bevy::time::Time;
|
use bevy::time::Time;
|
||||||
@@ -34,9 +35,11 @@ use bevy_mod_openxr::init::{should_run_frame_loop, OxrInitPlugin};
|
|||||||
use bevy_mod_openxr::render::{update_cameras, OxrRenderPlugin};
|
use bevy_mod_openxr::render::{update_cameras, OxrRenderPlugin};
|
||||||
use bevy_mod_openxr::resources::{OxrFrameState, OxrFrameWaiter, OxrGraphicsInfo};
|
use bevy_mod_openxr::resources::{OxrFrameState, OxrFrameWaiter, OxrGraphicsInfo};
|
||||||
use bevy_mod_openxr::session::OxrSession;
|
use bevy_mod_openxr::session::OxrSession;
|
||||||
|
use bevy_mod_openxr::spaces::OxrSpaceExt;
|
||||||
use bevy_mod_openxr::types::{AppInfo, Version};
|
use bevy_mod_openxr::types::{AppInfo, Version};
|
||||||
use bevy_mod_openxr::{add_xr_plugins, openxr_session_running};
|
use bevy_mod_openxr::{add_xr_plugins, openxr_session_running};
|
||||||
use bevy_mod_xr::session::{XrFirst, XrSessionCreated, XrSessionPlugin};
|
use bevy_mod_xr::session::{XrFirst, XrPreDestroySession, XrSessionCreated, XrSessionPlugin};
|
||||||
|
use bevy_mod_xr::spaces::XrPrimaryReferenceSpace;
|
||||||
use bevy_plugin::{DbusConnection, InputUpdate, StardustBevyPlugin, StardustFirst};
|
use bevy_plugin::{DbusConnection, InputUpdate, StardustBevyPlugin, StardustFirst};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use core::client::Client;
|
use core::client::Client;
|
||||||
@@ -47,6 +50,7 @@ use nodes::drawable::lines::BevyLinesPlugin;
|
|||||||
use nodes::drawable::model::StardustModelPlugin;
|
use nodes::drawable::model::StardustModelPlugin;
|
||||||
use nodes::drawable::text::StardustTextPlugin;
|
use nodes::drawable::text::StardustTextPlugin;
|
||||||
use objects::input::sk_controller::StardustControllerPlugin;
|
use objects::input::sk_controller::StardustControllerPlugin;
|
||||||
|
use objects::input::sk_hand::StardustHandPlugin;
|
||||||
use objects::ServerObjects;
|
use objects::ServerObjects;
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use openxr::OverlaySessionCreateFlagsEXTX;
|
use openxr::OverlaySessionCreateFlagsEXTX;
|
||||||
@@ -260,7 +264,7 @@ fn stereokit_loop(
|
|||||||
exts
|
exts
|
||||||
},
|
},
|
||||||
blend_modes: Some(vec![
|
blend_modes: Some(vec![
|
||||||
// openxr::EnvironmentBlendMode::ALPHA_BLEND,
|
openxr::EnvironmentBlendMode::ALPHA_BLEND,
|
||||||
openxr::EnvironmentBlendMode::OPAQUE,
|
openxr::EnvironmentBlendMode::OPAQUE,
|
||||||
]),
|
]),
|
||||||
synchronous_pipeline_compilation: false,
|
synchronous_pipeline_compilation: false,
|
||||||
@@ -283,6 +287,7 @@ fn stereokit_loop(
|
|||||||
bevy_app.add_plugins((
|
bevy_app.add_plugins((
|
||||||
BevyLinesPlugin,
|
BevyLinesPlugin,
|
||||||
StardustModelPlugin,
|
StardustModelPlugin,
|
||||||
|
StardustHandPlugin,
|
||||||
StardustTextPlugin,
|
StardustTextPlugin,
|
||||||
StardustSoundPlugin,
|
StardustSoundPlugin,
|
||||||
StardustControllerPlugin,
|
StardustControllerPlugin,
|
||||||
@@ -326,10 +331,36 @@ fn stereokit_loop(
|
|||||||
cams.iter().for_each(|e| {
|
cams.iter().for_each(|e| {
|
||||||
cmds.entity(e).remove::<Skybox>();
|
cmds.entity(e).remove::<Skybox>();
|
||||||
});
|
});
|
||||||
|
cmds.insert_resource(ClearColor(Color::NONE));
|
||||||
}
|
}
|
||||||
*last_hidden = env_hidden;
|
*last_hidden = env_hidden;
|
||||||
}
|
}
|
||||||
bevy_app.add_systems(XrSessionCreated, update_background);
|
bevy_app.add_systems(XrSessionCreated, update_background);
|
||||||
|
bevy_app.add_systems(
|
||||||
|
PostUpdate,
|
||||||
|
(|mut objects: ResMut<ServerObjects>,
|
||||||
|
ref_space: Res<XrPrimaryReferenceSpace>,
|
||||||
|
session: Res<OxrSession>| {
|
||||||
|
objects
|
||||||
|
.ref_space
|
||||||
|
.replace(unsafe { ref_space.as_openxr_space(&session) });
|
||||||
|
objects.view_space.replace(
|
||||||
|
session
|
||||||
|
.deref()
|
||||||
|
.deref()
|
||||||
|
.create_reference_space(
|
||||||
|
openxr::ReferenceSpaceType::VIEW,
|
||||||
|
openxr::Posef::IDENTITY,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.run_if(on_event::<bevy_mod_xr::session::XrSessionCreatedEvent>),
|
||||||
|
);
|
||||||
|
bevy_app.add_systems(XrPreDestroySession, |mut objetcs: ResMut<ServerObjects>| {
|
||||||
|
objetcs.ref_space = None;
|
||||||
|
objetcs.view_space = None;
|
||||||
|
});
|
||||||
bevy_app.add_systems(
|
bevy_app.add_systems(
|
||||||
Update,
|
Update,
|
||||||
update_background.run_if(on_event::<OxrOverlaySessionEvent>),
|
update_background.run_if(on_event::<OxrOverlaySessionEvent>),
|
||||||
|
|||||||
@@ -163,8 +163,18 @@ impl Drop for Sound {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
<<<<<<< HEAD
|
||||||
|
create_interface!(AudioInterface);
|
||||||
|
>>>>>>> 0ec4c0f (refactor: get models fully working)
|
||||||
struct AudioInterface;
|
struct AudioInterface;
|
||||||
impl InterfaceAspect for AudioInterface {
|
impl InterfaceAspect for AudioInterface {
|
||||||
|
=======
|
||||||
|
pub fn update() {}
|
||||||
|
|
||||||
|
impl InterfaceAspect for Interface {
|
||||||
|
>>>>>>> 2f5c92d (refactor: get models fully working)
|
||||||
#[doc = "Create a sound node. WAV and MP3 are supported."]
|
#[doc = "Create a sound node. WAV and MP3 are supported."]
|
||||||
fn create_sound(
|
fn create_sound(
|
||||||
_node: Arc<Node>,
|
_node: Arc<Node>,
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ pub fn draw_all(
|
|||||||
let mat_handle = materials.add(material);
|
let mat_handle = materials.add(material);
|
||||||
for lines in LINES_REGISTRY.get_valid_contents() {
|
for lines in LINES_REGISTRY.get_valid_contents() {
|
||||||
if let Some(node) = lines.space.node() {
|
if let Some(node) = lines.space.node() {
|
||||||
if node.enabled() {
|
if node.enabled() && !lines.data.lock().is_empty() {
|
||||||
// Does this rebuild the mesh every frame? yes, is this problematic? probably,
|
// Does this rebuild the mesh every frame? yes, is this problematic? probably,
|
||||||
// would a shader work better? yes, do i care? not right now
|
// would a shader work better? yes, do i care? not right now
|
||||||
let mut mesh = Mesh::new(
|
let mut mesh = Mesh::new(
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use super::{MaterialParameter, ModelAspect, ModelPartAspect, MODEL_PART_ASPECT_ALIAS_INFO};
|
use super::{MaterialParameter, ModelAspect, ModelPartAspect, MODEL_PART_ASPECT_ALIAS_INFO};
|
||||||
use crate::bail;
|
use crate::bail;
|
||||||
use crate::bevy_plugin::MainWorldEntity;
|
use crate::bevy_plugin::{MainWorldEntity, DESTROY_ENTITY};
|
||||||
use crate::core::client::Client;
|
use crate::core::client::Client;
|
||||||
use crate::core::error::Result;
|
use crate::core::error::Result;
|
||||||
use crate::core::registry::Registry;
|
use crate::core::registry::Registry;
|
||||||
@@ -8,8 +8,8 @@ use crate::core::resource::get_resource_file;
|
|||||||
use crate::nodes::alias::{Alias, AliasList};
|
use crate::nodes::alias::{Alias, AliasList};
|
||||||
use crate::nodes::spatial::Spatial;
|
use crate::nodes::spatial::Spatial;
|
||||||
use crate::nodes::Node;
|
use crate::nodes::Node;
|
||||||
use crate::DefaultMaterial;
|
use crate::{DefaultMaterial, TOKIO};
|
||||||
use bevy::app::{Plugin, PostUpdate};
|
use bevy::app::{Plugin, PostUpdate, PreUpdate, Update};
|
||||||
use bevy::asset::{AssetServer, Assets};
|
use bevy::asset::{AssetServer, Assets};
|
||||||
use bevy::color::{Alpha, Color, LinearRgba, Srgba};
|
use bevy::color::{Alpha, Color, LinearRgba, Srgba};
|
||||||
use bevy::core::Name;
|
use bevy::core::Name;
|
||||||
@@ -18,23 +18,27 @@ use bevy::math::bounding::Aabb3d;
|
|||||||
use bevy::pbr::MeshMaterial3d;
|
use bevy::pbr::MeshMaterial3d;
|
||||||
use bevy::prelude::AlphaMode;
|
use bevy::prelude::AlphaMode;
|
||||||
use bevy::prelude::{
|
use bevy::prelude::{
|
||||||
Children, Commands, Component, Deref, Entity, HierarchyQueryExt, Mesh3d, Parent, Query, Res,
|
BuildChildrenTransformExt, Children, Commands, Component, Deref, Entity, Has,
|
||||||
ResMut, Resource, Transform, Visibility, With, Without,
|
HierarchyQueryExt, Mesh3d, Parent, Query, Res, ResMut, Resource, Transform, Visibility, With,
|
||||||
|
Without,
|
||||||
};
|
};
|
||||||
use bevy::reflect::{GetField, PartialReflect, Reflect};
|
use bevy::reflect::{GetField, PartialReflect, Reflect};
|
||||||
use bevy::render::primitives::Aabb;
|
use bevy::render::primitives::Aabb;
|
||||||
use bevy::scene::SceneRoot;
|
use bevy::scene::SceneRoot;
|
||||||
use color_eyre::eyre::eyre;
|
use color_eyre::eyre::eyre;
|
||||||
use glam::{Vec2, Vec3};
|
use bevy::tasks::futures_lite::FutureExt;
|
||||||
|
use glam::{Mat4, Vec2, Vec3};
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use stardust_xr::values::ResourceID;
|
use stardust_xr::values::ResourceID;
|
||||||
use tracing::{error, warn};
|
use tokio::sync::Notify;
|
||||||
|
use tracing::{error, info, warn};
|
||||||
|
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
|
use std::future::IntoFuture;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::path::PathBuf;
|
use std::path::{self, PathBuf};
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
|
|
||||||
static MODEL_REGISTRY: Registry<Model> = Registry::new();
|
static MODEL_REGISTRY: Registry<Model> = Registry::new();
|
||||||
@@ -132,7 +136,7 @@ impl MaterialParameter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct ModelPart {
|
pub struct ModelPart {
|
||||||
entity: MainWorldEntity,
|
entity: OnceCell<Entity>,
|
||||||
path: String,
|
path: String,
|
||||||
space: Arc<Spatial>,
|
space: Arc<Spatial>,
|
||||||
model: Weak<Model>,
|
model: Weak<Model>,
|
||||||
@@ -142,7 +146,7 @@ pub struct ModelPart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component, Clone)]
|
#[derive(Component, Clone)]
|
||||||
pub struct StardustModel(Arc<Model>);
|
pub struct StardustModel(Weak<Model>);
|
||||||
#[derive(Component, Clone)]
|
#[derive(Component, Clone)]
|
||||||
pub struct UnprocessedModel;
|
pub struct UnprocessedModel;
|
||||||
pub struct StardustModelPlugin;
|
pub struct StardustModelPlugin;
|
||||||
@@ -151,7 +155,10 @@ impl Plugin for StardustModelPlugin {
|
|||||||
let (tx, rx) = crossbeam_channel::unbounded();
|
let (tx, rx) = crossbeam_channel::unbounded();
|
||||||
LOAD_MODEL_SENDER.set(tx);
|
LOAD_MODEL_SENDER.set(tx);
|
||||||
app.insert_resource(LoadModelReader(rx));
|
app.insert_resource(LoadModelReader(rx));
|
||||||
app.add_systems(PostUpdate, create_model_parts_for_loaded_models);
|
app.add_systems(Update, create_model_parts_for_loaded_models);
|
||||||
|
app.add_systems(PreUpdate, load_models);
|
||||||
|
app.add_systems(PostUpdate, update_models);
|
||||||
|
app.add_systems(PostUpdate, update_model_parts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static LOAD_MODEL_SENDER: OnceCell<crossbeam_channel::Sender<(PathBuf, Arc<Model>)>> =
|
static LOAD_MODEL_SENDER: OnceCell<crossbeam_channel::Sender<(PathBuf, Arc<Model>)>> =
|
||||||
@@ -161,8 +168,11 @@ struct LoadModelReader(crossbeam_channel::Receiver<(PathBuf, Arc<Model>)>);
|
|||||||
|
|
||||||
fn update_models(mut query: Query<(&StardustModel, &mut Visibility, &mut Transform)>) {
|
fn update_models(mut query: Query<(&StardustModel, &mut Visibility, &mut Transform)>) {
|
||||||
for (model, mut vis, mut transform) in query.iter_mut() {
|
for (model, mut vis, mut transform) in query.iter_mut() {
|
||||||
*transform = Transform::from_matrix(model.0.space.global_transform());
|
let Some(model) = model.0.upgrade() else {
|
||||||
if let Some(node) = model.0.space.node() {
|
continue;
|
||||||
|
};
|
||||||
|
*transform = Transform::from_matrix(model.space.global_transform());
|
||||||
|
if let Some(node) = model.space.node() {
|
||||||
*vis = match node.enabled() {
|
*vis = match node.enabled() {
|
||||||
true => Visibility::Inherited,
|
true => Visibility::Inherited,
|
||||||
false => Visibility::Hidden,
|
false => Visibility::Hidden,
|
||||||
@@ -177,7 +187,7 @@ fn load_models(rx: Res<LoadModelReader>, mut cmds: Commands, asset_server: Res<A
|
|||||||
let entity = cmds
|
let entity = cmds
|
||||||
.spawn((
|
.spawn((
|
||||||
SceneRoot(handle),
|
SceneRoot(handle),
|
||||||
StardustModel(model.clone()),
|
StardustModel(Arc::downgrade(&model)),
|
||||||
UnprocessedModel,
|
UnprocessedModel,
|
||||||
))
|
))
|
||||||
.id();
|
.id();
|
||||||
@@ -186,29 +196,32 @@ fn load_models(rx: Res<LoadModelReader>, mut cmds: Commands, asset_server: Res<A
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn update_model_parts(
|
fn update_model_parts(
|
||||||
models: Query<&StardustModel>,
|
models: Query<&StardustModel, Without<UnprocessedModel>>,
|
||||||
mut mats: ResMut<Assets<DefaultMaterial>>,
|
mut mats: ResMut<Assets<DefaultMaterial>>,
|
||||||
mut part_query: Query<(
|
mut part_query: Query<(
|
||||||
&mut Transform,
|
&mut Transform,
|
||||||
&mut MeshMaterial3d<DefaultMaterial>,
|
&mut MeshMaterial3d<DefaultMaterial>,
|
||||||
&mut Mesh3d,
|
Has<Parent>,
|
||||||
)>,
|
)>,
|
||||||
|
mut cmds: Commands,
|
||||||
) {
|
) {
|
||||||
for model in &models {
|
for model in &models {
|
||||||
let model = &model.0;
|
let Some(model) = model.0.upgrade() else {
|
||||||
for part in model.parts.lock().iter() {
|
|
||||||
let Ok((mut transform, mut mat, mut _mesh)) = part_query.get_mut(*part.entity) else {
|
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
*transform = Transform::from_matrix(Spatial::space_to_space_matrix(
|
for part in model.parts.lock().iter() {
|
||||||
Some(&part.space),
|
let Some((entity, (mut transform, mut mat, has_parent))) = part
|
||||||
Some(&model.space),
|
.entity
|
||||||
));
|
.get()
|
||||||
if let Some(material_replacement) = part.pending_material_replacement.lock().take() {
|
.and_then(|e| Some((*e, part_query.get_mut(*e).ok()?)))
|
||||||
let material = material_replacement.deref().clone();
|
else {
|
||||||
let mat_handle = mats.add(material);
|
continue;
|
||||||
mat.0 = mat_handle;
|
};
|
||||||
|
if has_parent {
|
||||||
|
cmds.entity(entity).remove_parent_in_place();
|
||||||
}
|
}
|
||||||
|
*transform = Transform::from_matrix(part.space.global_transform());
|
||||||
|
|
||||||
// todo: find all materials with identical parameters and batch them into 1 material again
|
// todo: find all materials with identical parameters and batch them into 1 material again
|
||||||
'mat_params: {
|
'mat_params: {
|
||||||
let mut material_parameters = part.pending_material_parameters.lock();
|
let mut material_parameters = part.pending_material_parameters.lock();
|
||||||
@@ -237,36 +250,41 @@ fn update_model_parts(
|
|||||||
|
|
||||||
fn get_path(
|
fn get_path(
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
query: &Query<(Entity, Option<&Parent>, &Transform, &Name, &Aabb), Without<SceneRoot>>,
|
query: &Query<(&Parent, &Name), Without<SceneRoot>>,
|
||||||
) -> Option<String> {
|
mut in_vec: Vec<String>,
|
||||||
let (_, parent, _, name, _) = query.get(entity).ok()?;
|
) -> Vec<String> {
|
||||||
let next = parent.and_then(|p| get_path(p.get(), query));
|
let Ok((parent, name)) = query.get(entity) else {
|
||||||
match next {
|
return in_vec;
|
||||||
Some(next) => Some(format!("{name}/{next}")),
|
};
|
||||||
None => Some(name.to_string()),
|
in_vec.push(name.to_string());
|
||||||
}
|
get_path(parent.get(), query, in_vec)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_model_parts_for_loaded_models(
|
fn create_model_parts_for_loaded_models(
|
||||||
query: Query<(Entity, &StardustModel), With<UnprocessedModel>>,
|
query: Query<(Entity, &StardustModel), (With<UnprocessedModel>, With<Children>)>,
|
||||||
children: Query<&Children>,
|
children: Query<&Children>,
|
||||||
gltf_model_parts: Query<
|
gltf_model_parts: Query<(Entity, &Transform, &Aabb), Without<SceneRoot>>,
|
||||||
(Entity, Option<&Parent>, &Transform, &Name, &Aabb),
|
name_query: Query<(&Parent, &Name), Without<SceneRoot>>,
|
||||||
Without<SceneRoot>,
|
|
||||||
>,
|
|
||||||
mut cmds: Commands,
|
mut cmds: Commands,
|
||||||
) {
|
) {
|
||||||
for (entity, model) in &query {
|
for (entity, model) in &query {
|
||||||
let model = &model.0;
|
info!("creating parts!");
|
||||||
let mut parts = model.parts.lock();
|
let Some(model) = model.0.upgrade() else {
|
||||||
cmds.entity(entity).remove::<UnprocessedModel>();
|
continue;
|
||||||
for (entity, parent, transform, name, aabb) in children
|
};
|
||||||
.iter_descendants(entity)
|
// let mut parts = model.parts.lock();
|
||||||
|
let mut parts = Vec::<Arc<ModelPart>>::new();
|
||||||
|
for (entity, transform, aabb) in children
|
||||||
|
.iter_descendants_depth_first(entity)
|
||||||
.filter_map(|e| gltf_model_parts.get(e).ok())
|
.filter_map(|e| gltf_model_parts.get(e).ok())
|
||||||
{
|
{
|
||||||
let parent_part = parent
|
let mut path_parts = get_path(entity, &name_query, Vec::new());
|
||||||
.and_then(|e| gltf_model_parts.get(e.get()).ok())
|
path_parts.remove(0);
|
||||||
.and_then(|(e, _, _, _, _)| parts.iter().find(|v| v.entity.0 == e));
|
path_parts.reverse();
|
||||||
|
let part_path = path_parts.join("/");
|
||||||
|
path_parts.pop();
|
||||||
|
let parent_path = path_parts.join("/");
|
||||||
|
let parent_part = parts.iter().find(|v| v.path == parent_path);
|
||||||
|
|
||||||
let Some(stardust_model_part) = model.space.node() else {
|
let Some(stardust_model_part) = model.space.node() else {
|
||||||
continue;
|
continue;
|
||||||
@@ -274,12 +292,40 @@ fn create_model_parts_for_loaded_models(
|
|||||||
let Some(client) = stardust_model_part.get_client() else {
|
let Some(client) = stardust_model_part.get_client() else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let part_path = get_path(entity, &gltf_model_parts).unwrap_or_else(|| name.to_string());
|
let model_part = model
|
||||||
|
.parts
|
||||||
|
.lock()
|
||||||
|
.iter()
|
||||||
|
.find(|v| v.path == part_path)
|
||||||
|
.cloned()
|
||||||
|
.map(|v| {
|
||||||
|
*v.space.bounding_box_calc.lock() = Aabb3d::new(aabb.center, aabb.half_extents);
|
||||||
|
if v.entity.set(entity).is_err() {
|
||||||
|
error!(
|
||||||
|
"trying to set entity for already init model part?!
|
||||||
|
please yell at schmarni if you see this"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(err) = v.space.set_spatial_parent(Some(
|
||||||
|
parent_part.map(|n| &n.space).unwrap_or_else(|| {
|
||||||
|
info!("model is spatial parent");
|
||||||
|
&model.space
|
||||||
|
}),
|
||||||
|
)) {
|
||||||
|
error!("error setting spatial parent for existing model part: {err}");
|
||||||
|
}
|
||||||
|
v.space.set_local_transform(transform.compute_matrix());
|
||||||
|
info!("not fresh {}", &v.path);
|
||||||
|
v
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| {
|
||||||
let node = client.scenegraph.add_node(Node::generate(&client, false));
|
let node = client.scenegraph.add_node(Node::generate(&client, false));
|
||||||
let spatial_parent = parent_part
|
let spatial_parent =
|
||||||
.map(|n| n.space.clone())
|
parent_part.map(|n| n.space.clone()).unwrap_or_else(|| {
|
||||||
.unwrap_or_else(|| model.space.clone());
|
info!("model is spatial parent");
|
||||||
|
model.space.clone()
|
||||||
|
});
|
||||||
|
|
||||||
let space = Spatial::add_to(
|
let space = Spatial::add_to(
|
||||||
&node,
|
&node,
|
||||||
@@ -290,6 +336,7 @@ fn create_model_parts_for_loaded_models(
|
|||||||
|
|
||||||
*space.bounding_box_calc.lock() = Aabb3d::new(aabb.center, aabb.half_extents);
|
*space.bounding_box_calc.lock() = Aabb3d::new(aabb.center, aabb.half_extents);
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
let model_part = Arc::new(ModelPart {
|
let model_part = Arc::new(ModelPart {
|
||||||
entity: MainWorldEntity(entity),
|
entity: MainWorldEntity(entity),
|
||||||
path: part_path,
|
path: part_path,
|
||||||
@@ -300,8 +347,26 @@ fn create_model_parts_for_loaded_models(
|
|||||||
aliases: AliasList::default(),
|
aliases: AliasList::default(),
|
||||||
});
|
});
|
||||||
node.add_aspect_raw(model_part.clone());
|
node.add_aspect_raw(model_part.clone());
|
||||||
|
=======
|
||||||
|
let model_part = Arc::new(ModelPart {
|
||||||
|
entity: OnceCell::from(entity),
|
||||||
|
path: part_path,
|
||||||
|
space,
|
||||||
|
model: Arc::downgrade(&model),
|
||||||
|
pending_material_parameters: Mutex::new(FxHashMap::default()),
|
||||||
|
pending_material_replacement: Mutex::new(None),
|
||||||
|
aliases: AliasList::default(),
|
||||||
|
});
|
||||||
|
node.add_aspect_raw(model_part.clone());
|
||||||
|
info!("fresh {}", &model_part.path);
|
||||||
|
model_part
|
||||||
|
});
|
||||||
|
>>>>>>> 0ec4c0f (refactor: get models fully working)
|
||||||
parts.push(model_part.clone());
|
parts.push(model_part.clone());
|
||||||
}
|
}
|
||||||
|
cmds.entity(entity).remove::<UnprocessedModel>();
|
||||||
|
info!("created parts! {}", parts.len());
|
||||||
|
*model.parts.lock() = parts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,11 +440,43 @@ impl ModelAspect for Model {
|
|||||||
part_path: String,
|
part_path: String,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let model = node.get_aspect::<Model>()?;
|
let model = node.get_aspect::<Model>()?;
|
||||||
|
<<<<<<< HEAD
|
||||||
let parts = model.parts.lock();
|
let parts = model.parts.lock();
|
||||||
let Some(part) = parts.iter().find(|p| p.path == part_path) else {
|
let Some(part) = parts.iter().find(|p| p.path == part_path) else {
|
||||||
let paths = parts.iter().map(|p| &p.path).collect::<Vec<_>>();
|
let paths = parts.iter().map(|p| &p.path).collect::<Vec<_>>();
|
||||||
bail!("Couldn't find model part at path {part_path}, all available paths: {paths:?}",);
|
bail!("Couldn't find model part at path {part_path}, all available paths: {paths:?}",);
|
||||||
};
|
};
|
||||||
|
=======
|
||||||
|
let mut parts = model.parts.lock();
|
||||||
|
let part =
|
||||||
|
parts
|
||||||
|
.iter()
|
||||||
|
.find(|p| p.path == part_path)
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
let paths = parts.iter().map(|p| &p.path).collect::<Vec<_>>();
|
||||||
|
error!("Couldn't find model part at path {part_path}, all available paths: {paths:?}");
|
||||||
|
|
||||||
|
let node = calling_client
|
||||||
|
.scenegraph
|
||||||
|
.add_node(Node::generate(&calling_client, false));
|
||||||
|
|
||||||
|
let space = Spatial::add_to(&node, None, Mat4::IDENTITY, false);
|
||||||
|
|
||||||
|
let model_part = Arc::new(ModelPart {
|
||||||
|
entity: OnceCell::new(),
|
||||||
|
path: part_path,
|
||||||
|
space,
|
||||||
|
model: Arc::downgrade(&model),
|
||||||
|
pending_material_parameters: Mutex::new(FxHashMap::default()),
|
||||||
|
pending_material_replacement: Mutex::new(None),
|
||||||
|
aliases: AliasList::default(),
|
||||||
|
});
|
||||||
|
node.add_aspect_raw(model_part.clone());
|
||||||
|
parts.push(model_part.clone());
|
||||||
|
model_part
|
||||||
|
});
|
||||||
|
>>>>>>> 0ec4c0f (refactor: get models fully working)
|
||||||
Alias::create_with_id(
|
Alias::create_with_id(
|
||||||
&part.space.node().unwrap(),
|
&part.space.node().unwrap(),
|
||||||
&calling_client,
|
&calling_client,
|
||||||
@@ -390,8 +487,18 @@ impl ModelAspect for Model {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl Drop for ModelPart {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if let Some(e) = self.entity.get() {
|
||||||
|
_ = DESTROY_ENTITY.send(*e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
impl Drop for Model {
|
impl Drop for Model {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
if let Some(e) = self.entity.get() {
|
||||||
|
_ = DESTROY_ENTITY.send(*e);
|
||||||
|
}
|
||||||
MODEL_REGISTRY.remove(self);
|
MODEL_REGISTRY.remove(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use crate::nodes::{
|
|||||||
};
|
};
|
||||||
use crate::objects::{ObjectHandle, SpatialRef};
|
use crate::objects::{ObjectHandle, SpatialRef};
|
||||||
use crate::DefaultMaterial;
|
use crate::DefaultMaterial;
|
||||||
|
use bevy::app::{Plugin, PostUpdate};
|
||||||
use bevy::asset::{AssetServer, Assets, Handle};
|
use bevy::asset::{AssetServer, Assets, Handle};
|
||||||
use bevy::prelude::{Commands, Component, Entity, Query, Res, ResMut};
|
use bevy::prelude::{Commands, Component, Entity, Query, Res, ResMut};
|
||||||
use bevy_mod_openxr::helper_traits::{ToQuat, ToVec3};
|
use bevy_mod_openxr::helper_traits::{ToQuat, ToVec3};
|
||||||
@@ -17,6 +18,7 @@ use bevy_mod_openxr::resources::OxrFrameState;
|
|||||||
use bevy_mod_openxr::session::OxrSession;
|
use bevy_mod_openxr::session::OxrSession;
|
||||||
use bevy_mod_openxr::spaces::OxrSpaceLocationFlags;
|
use bevy_mod_openxr::spaces::OxrSpaceLocationFlags;
|
||||||
use bevy_mod_xr::hands::{HandBone, HandSide};
|
use bevy_mod_xr::hands::{HandBone, HandSide};
|
||||||
|
use bevy_mod_xr::session::XrSessionCreated;
|
||||||
use bevy_mod_xr::spaces::XrPrimaryReferenceSpace;
|
use bevy_mod_xr::spaces::XrPrimaryReferenceSpace;
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use glam::{Mat4, Quat, Vec3};
|
use glam::{Mat4, Quat, Vec3};
|
||||||
@@ -34,6 +36,14 @@ fn update_joint(joint: &mut Joint, oxr_joint: openxr::HandJointLocation) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct StardustHandPlugin;
|
||||||
|
impl Plugin for StardustHandPlugin {
|
||||||
|
fn build(&self, app: &mut bevy::prelude::App) {
|
||||||
|
app.add_systems(XrSessionCreated, create_hands);
|
||||||
|
app.add_systems(PostUpdate, update_hands);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn update_hands(
|
fn update_hands(
|
||||||
mut mats: ResMut<Assets<DefaultMaterial>>,
|
mut mats: ResMut<Assets<DefaultMaterial>>,
|
||||||
mut query: Query<&mut SkHand>,
|
mut query: Query<&mut SkHand>,
|
||||||
@@ -76,7 +86,7 @@ fn update_hands(
|
|||||||
update_joint(&mut finger.distal, joints[finger_index + 3]);
|
update_joint(&mut finger.distal, joints[finger_index + 3]);
|
||||||
update_joint(&mut finger.intermediate, joints[finger_index + 2]);
|
update_joint(&mut finger.intermediate, joints[finger_index + 2]);
|
||||||
update_joint(&mut finger.proximal, joints[finger_index + 1]);
|
update_joint(&mut finger.proximal, joints[finger_index + 1]);
|
||||||
update_joint(&mut finger.metacarpal, joints[finger_index + 0]);
|
update_joint(&mut finger.metacarpal, joints[finger_index]);
|
||||||
// Why?
|
// Why?
|
||||||
finger.tip.radius = 0.0;
|
finger.tip.radius = 0.0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ use openxr::SpaceLocationFlags;
|
|||||||
use play_space::PlaySpaceBounds;
|
use play_space::PlaySpaceBounds;
|
||||||
use stardust_xr::schemas::dbus::object_registry::ObjectRegistry;
|
use stardust_xr::schemas::dbus::object_registry::ObjectRegistry;
|
||||||
use std::{marker::PhantomData, sync::Arc};
|
use std::{marker::PhantomData, sync::Arc};
|
||||||
|
use tracing::info;
|
||||||
use zbus::{interface, object_server::Interface, zvariant::OwnedObjectPath, Connection};
|
use zbus::{interface, object_server::Interface, zvariant::OwnedObjectPath, Connection};
|
||||||
|
|
||||||
pub mod input;
|
pub mod input;
|
||||||
@@ -54,8 +55,8 @@ pub struct ServerObjects {
|
|||||||
hmd: (Arc<Spatial>, ObjectHandle<SpatialRef>),
|
hmd: (Arc<Spatial>, ObjectHandle<SpatialRef>),
|
||||||
play_space: Option<(Arc<Spatial>, ObjectHandle<SpatialRef>)>,
|
play_space: Option<(Arc<Spatial>, ObjectHandle<SpatialRef>)>,
|
||||||
inputs: Option<Inputs>,
|
inputs: Option<Inputs>,
|
||||||
view_space: Option<openxr::Space>,
|
pub view_space: Option<openxr::Space>,
|
||||||
ref_space: Option<openxr::Space>,
|
pub ref_space: Option<openxr::Space>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TrackingRefs {
|
pub struct TrackingRefs {
|
||||||
@@ -125,7 +126,7 @@ impl ServerObjects {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(
|
pub(crate) fn update(
|
||||||
&mut self,
|
&mut self,
|
||||||
session: Option<&openxr::Session<openxr::AnyGraphics>>,
|
session: Option<&openxr::Session<openxr::AnyGraphics>>,
|
||||||
time: Option<openxr::Time>,
|
time: Option<openxr::Time>,
|
||||||
|
|||||||
Reference in New Issue
Block a user