refactor: begin conversion to bevy, do proper frame wait

Signed-off-by: Schmarni <marnistromer@gmail.com>
This commit is contained in:
Schmarni
2024-12-15 00:01:32 +01:00
parent 8708f240b4
commit 9f4420f6c9
11 changed files with 680 additions and 4303 deletions

View File

@@ -6,122 +6,117 @@ use crate::core::registry::Registry;
use crate::core::resource::get_resource_file;
use crate::nodes::alias::{Alias, AliasList};
use crate::nodes::spatial::Spatial;
use crate::nodes::Node;
use crate::nodes::{Aspect, Node};
use crate::DefaultMaterial;
use bevy::app::Plugin;
use bevy::asset::Handle;
use bevy::color::{Alpha, Color, LinearRgba, Srgba};
use bevy::prelude::AlphaMode;
use bevy::reflect::{GetField, PartialReflect, Reflect};
use color_eyre::eyre::eyre;
use glam::{Mat4, Vec2, Vec3};
use once_cell::sync::{Lazy, OnceCell};
use parking_lot::Mutex;
use rustc_hash::FxHashMap;
use stardust_xr::values::ResourceID;
use tracing::warn;
use std::ffi::OsStr;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use std::sync::{Arc, Weak};
use stereokit_rust::material::Transparency;
use stereokit_rust::maths::Bounds;
use stereokit_rust::sk::MainThreadToken;
use stereokit_rust::{material::Material, model::Model as SKModel, tex::Tex, util::Color128};
pub struct MaterialWrapper(pub Material);
impl Hash for MaterialWrapper {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.get_shader().0.as_ptr().hash(state);
for param in self.0.get_all_param_info() {
param.to_string().hash(state)
}
self.0.get_chain().map(MaterialWrapper).hash(state)
}
}
impl PartialEq for MaterialWrapper {
fn eq(&self, other: &Self) -> bool {
if self.0.get_shader().0.as_ptr() != other.0.get_shader().0.as_ptr() {
return false;
}
if self.0.get_all_param_info().count() != other.0.get_all_param_info().count() {
return false;
}
for self_param in self.0.get_all_param_info() {
let Some(other_param) = other
.0
.get_all_param_info()
.get_data(self_param.get_name(), self_param.get_type())
else {
return false;
};
if self_param.to_string() != other_param.to_string() {
return false;
}
}
self.0.get_chain().map(MaterialWrapper) == other.0.get_chain().map(MaterialWrapper)
}
}
impl Eq for MaterialWrapper {}
unsafe impl Send for MaterialWrapper {}
unsafe impl Sync for MaterialWrapper {}
#[derive(Default)]
struct MaterialRegistry(Mutex<FxHashMap<u64, String>>);
impl MaterialRegistry {
fn add_or_get(&self, material: Arc<MaterialWrapper>) -> Arc<MaterialWrapper> {
let mut lock = self.0.lock();
let hash = {
use std::hash::{Hash, Hasher};
let mut hasher = std::collections::hash_map::DefaultHasher::new();
material.hash(&mut hasher);
hasher.finish()
};
if let Some(id) = lock.get(&hash) {
if let Ok(existing) = Material::find(id) {
return Arc::new(MaterialWrapper(existing));
}
}
lock.insert(hash, material.0.get_id().to_string());
material
}
}
static MATERIAL_REGISTRY: Lazy<MaterialRegistry> = Lazy::new(MaterialRegistry::default);
static MODEL_REGISTRY: Registry<Model> = Registry::new();
static HOLDOUT_MATERIAL: OnceCell<Arc<MaterialWrapper>> = OnceCell::new();
static HOLDOUT_MATERIAL: OnceCell<Arc<DefaultMaterial>> = OnceCell::new();
impl MaterialParameter {
fn apply_to_material(&self, client: &Client, material: &Material, parameter_name: &str) {
let mut params = material.get_all_param_info();
fn apply_to_material(
&self,
client: &Client,
material: &mut DefaultMaterial,
parameter_name: &str,
) {
match self {
MaterialParameter::Bool(val) => {
params.set_bool(parameter_name, *val);
}
MaterialParameter::Int(val) => {
params.set_int(parameter_name, &[*val]);
}
MaterialParameter::UInt(val) => {
params.set_uint(parameter_name, &[*val]);
}
MaterialParameter::Float(val) => {
params.set_float(parameter_name, *val);
}
MaterialParameter::Vec2(val) => {
params.set_vec2(parameter_name, Vec2::from(*val));
}
MaterialParameter::Vec3(val) => {
params.set_vec3(parameter_name, Vec3::from(*val));
}
MaterialParameter::Color(val) => {
params.set_color(
parameter_name,
Color128::new(val.c.r, val.c.g, val.c.b, val.a),
);
}
MaterialParameter::Bool(val) => match parameter_name {
name => {
if let Some(field) = material.get_field_mut::<bool>(name) {
*field = *val;
} else {
warn!("unknown bool material parameter name: {name}");
}
}
},
MaterialParameter::Int(val) => match parameter_name {
name => {
if let Some(field) = material.get_field_mut::<i32>(name) {
*field = *val;
} else {
warn!("unknown bool material parameter name: {name}");
}
}
},
MaterialParameter::UInt(val) => match parameter_name {
name => {
if let Some(field) = material.get_field_mut::<u32>(name) {
*field = *val;
} else {
warn!("unknown bool material parameter name: {name}");
}
}
},
MaterialParameter::Float(val) => match parameter_name {
name => {
if let Some(field) = material.get_field_mut::<f32>(name) {
*field = *val;
} else {
warn!("unknown bool material parameter name: {name}");
}
}
},
MaterialParameter::Vec2(val) => match parameter_name {
name => {
if let Some(field) = material.get_field_mut::<Vec2>(name) {
*field = (*val).into();
} else {
warn!("unknown bool material parameter name: {name}");
}
}
},
MaterialParameter::Vec3(val) => match parameter_name {
name => {
if let Some(field) = material.get_field_mut::<Vec3>(name) {
*field = (*val).into();
} else {
warn!("unknown bool material parameter name: {name}");
}
}
},
MaterialParameter::Color(val) => match parameter_name {
"color" => {
material.base_color = LinearRgba::new(val.c.r, val.c.g, val.c.b, val.a).into()
}
name => {
if let Some(field) = material.get_field_mut::<Color>(name) {
*field = LinearRgba::new(val.c.r, val.c.g, val.c.b, val.a).into();
} else {
warn!("unknown bool material parameter name: {name}");
}
}
},
MaterialParameter::Texture(resource) => {
match parameter_name {
name => {
warn!("unknown texture material parameter name: {name}");
}
}
let Some(texture_path) =
get_resource_file(resource, client, &[OsStr::new("png"), OsStr::new("jpg")])
else {
return;
};
if let Ok(tex) = Tex::from_file(texture_path, true, None) {
params.set_texture(parameter_name, &tex);
}
// if let Ok(tex) = Tex::from_file(texture_path, true, None) {
// params.set_texture(parameter_name, &tex);
// }
}
}
}
@@ -133,16 +128,26 @@ pub struct ModelPart {
space: Arc<Spatial>,
model: Weak<Model>,
pending_material_parameters: Mutex<FxHashMap<String, MaterialParameter>>,
pending_material_replacement: Mutex<Option<Arc<MaterialWrapper>>>,
pending_material_replacement: Mutex<Option<Arc<Handle<DefaultMaterial>>>>,
aliases: AliasList,
}
pub struct StardustModelPlugin;
impl Plugin for StardustModelPlugin {
fn build(&self, app: &mut bevy::prelude::App) {}
}
impl ModelPart {
fn create_for_model(model: &Arc<Model>, sk_model: &SKModel) {
// The value isn't even used?!
HOLDOUT_MATERIAL.get_or_init(|| {
let mut mat = Material::copy(&Material::unlit());
mat.transparency(Transparency::None);
mat.color_tint(Color128::BLACK_TRANSPARENT);
Arc::new(MaterialWrapper(mat))
let mut mat = DefaultMaterial {
unlit: true,
alpha_mode: AlphaMode::Opaque,
base_color: Srgba::BLACK.with_alpha(0.0).into(),
..Default::default()
};
Arc::new(mat)
});
let nodes = sk_model.get_nodes();
@@ -307,7 +312,7 @@ impl ModelPartAspect for ModelPart {
pub struct Model {
space: Arc<Spatial>,
_resource_id: ResourceID,
sk_model: OnceCell<SKModel>,
sk_model: OnceCell<()>,
parts: Mutex<Vec<Arc<ModelPart>>>,
}
impl Model {