From bd05d9068b968e35e6aacbcb37a300d7ef31a76a Mon Sep 17 00:00:00 2001 From: Schmarni Date: Fri, 27 Jun 2025 21:40:36 +0200 Subject: [PATCH] feat(lines): line impl mostly done Signed-off-by: Schmarni --- Cargo.lock | 9 +- src/main.rs | 19 ++-- src/nodes/drawable/lines.rs | 169 +++++++++++++++++++++++++++++++++-- src/nodes/drawable/model.rs | 3 - src/objects/input/sk_hand.rs | 1 - 5 files changed, 177 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 102fd51..3404016 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6402,7 +6402,8 @@ dependencies = [ [[package]] name = "tracing-tracy" version = "0.11.4" -source = "git+https://github.com/nagisa/rust_tracy_client?tag=tracy-client-v0.18.1#7d084307f54959999ca3729c42bd4f4f3f0df54d" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eaa1852afa96e0fe9e44caa53dc0bd2d9d05e0f2611ce09f97f8677af56e4ba" dependencies = [ "tracing-core", "tracing-subscriber", @@ -6423,7 +6424,8 @@ dependencies = [ [[package]] name = "tracy-client" version = "0.18.1" -source = "git+https://github.com/nagisa/rust_tracy_client?tag=tracy-client-v0.18.1#7d084307f54959999ca3729c42bd4f4f3f0df54d" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3927832d93178f979a970d26deed7b03510586e328f31b0f9ad7a73985b8332a" dependencies = [ "loom", "once_cell", @@ -6433,7 +6435,8 @@ dependencies = [ [[package]] name = "tracy-client-sys" version = "0.25.0" -source = "git+https://github.com/nagisa/rust_tracy_client?tag=tracy-client-v0.18.1#7d084307f54959999ca3729c42bd4f4f3f0df54d" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c032d68a49d25d9012a864fef1c64ac17aee43c87e0477bf7301d8ae8bfea7b7" dependencies = [ "cc", "windows-targets 0.48.5", diff --git a/src/main.rs b/src/main.rs index 2edb0bc..1b52fe3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -44,6 +44,7 @@ use clap::Parser; use core::client::{Client, tick_internal_client}; use core::task; use directories::ProjectDirs; +use nodes::drawable::lines::LinesNodePlugin; use nodes::drawable::model::ModelNodePlugin; use nodes::drawable::text::TextNodePlugin; use nodes::spatial::SpatialNodePlugin; @@ -117,6 +118,13 @@ static STARDUST_INSTANCE: OnceLock = OnceLock::new(); // #[tokio::main(flavor = "current_thread")] #[tokio::main] async fn main() { + // let mut out = Vec::new(); + // for i in 0..8 { + // for base in [0, 8, 1, 8, 9, 1] { + // out.push(base + i as u16); + // } + // } + // panic!("{out:?}"); color_eyre::install().unwrap(); let registry = tracing_subscriber::registry(); @@ -387,6 +395,7 @@ fn bevy_loop( SpatialNodePlugin, ModelNodePlugin, TextNodePlugin, + LinesNodePlugin, PlaySpacePlugin, HandPlugin, ControllerPlugin, @@ -400,16 +409,6 @@ fn bevy_loop( .in_set(OxrWaitFrameSystem) .in_set(XrHandleEvents::FrameLoop), ); - use std::process::Command; - - let output = Command::new("fc-match") - .arg("-f") - .arg("%{file}") - .output() - .expect("Failed to run fc-match"); - - let font_path = String::from_utf8_lossy(&output.stdout); - info!("Default font path: {}", font_path); app.run(); } diff --git a/src/nodes/drawable/lines.rs b/src/nodes/drawable/lines.rs index d414e00..ebc5e12 100644 --- a/src/nodes/drawable/lines.rs +++ b/src/nodes/drawable/lines.rs @@ -1,20 +1,170 @@ use super::{Line, LinesAspect}; use crate::{ - core::{client::Client, error::Result, registry::Registry}, - nodes::{Node, spatial::Spatial}, + core::{client::Client, color::ColorConvert, error::Result, registry::Registry}, + nodes::{ + Node, + spatial::{Spatial, SpatialNode}, + }, }; +use bevy::{ + asset::RenderAssetUsages, + prelude::*, + render::mesh::{Indices, PrimitiveTopology}, +}; +use bevy_sk::vr_materials::PbrMaterial; use glam::{FloatExt, Vec3}; use parking_lot::Mutex; -use std::{collections::VecDeque, sync::Arc}; +use std::{ + collections::VecDeque, + sync::{ + Arc, OnceLock, + atomic::{AtomicBool, Ordering}, + }, +}; use stereokit_rust::{ maths::Bounds, sk::MainThreadToken, system::LinePoint as SkLinePoint, util::Color128, }; +pub struct LinesNodePlugin; + +impl Plugin for LinesNodePlugin { + fn build(&self, app: &mut App) { + app.add_systems(Update, build_line_mesh); + } +} +const POINTS: [Vec3; 8] = [ + Vec3::X, + Vec3::new(1., 0., 1.), + Vec3::Z, + Vec3::new(-1., 0., 1.), + Vec3::NEG_X, + Vec3::new(-1., 0., -1.), + Vec3::NEG_Z, + Vec3::new(1., 0., -1.), +]; + +fn build_line_mesh( + mut meshes: ResMut>, + mut cmds: Commands, + mut materials: ResMut>, +) { + for lines in LINES_REGISTRY + .get_valid_contents() + .into_iter() + .filter(|l| l.gen_mesh.load(Ordering::Relaxed)) + { + lines.gen_mesh.store(false, Ordering::Relaxed); + let mut vertex_positions = Vec::::new(); + let mut vertex_normals = Vec::::new(); + let mut vertex_colors = Vec::<[f32; 4]>::new(); + let mut vertex_indecies = Vec::::new(); + let lines_data = lines.data.lock(); + if lines_data.is_empty() { + continue; + } + + let mut idk = 0; + for line in lines_data.iter() { + let optional_points = { + let mut out = Vec::new(); + let mut last = line.cyclic.then(|| line.points.last()).flatten(); + let mut peekable = line.points.iter().peekable(); + while let Some(curr) = peekable.next() { + let next = match peekable.peek() { + Some(v) => Some(*v), + None => line.cyclic.then(|| line.points.first()).flatten(), + }; + + out.push((last, curr, next)); + last = Some(curr); + } + out + }; + for (last, curr, next) in optional_points { + let last_quat = last.map(|v| { + Quat::from_rotation_arc( + Vec3::Y, + (Vec3::from(curr.point) - Vec3::from(v.point)).normalize(), + ) + }); + let next_quat = next.map(|v| { + Quat::from_rotation_arc( + Vec3::Y, + (Vec3::from(v.point) - Vec3::from(curr.point)).normalize(), + ) + }); + let quat = match (last_quat, next_quat) { + (None, None) => unreachable!(), + (None, Some(next)) => next, + (Some(last), None) => last, + (Some(last), Some(next)) => last.lerp(next, 0.5), + }; + let normals = [ + Vec3::X, + Vec3::new(1., 0., 1.).normalize(), + Vec3::Z, + Vec3::new(-1., 0., 1.).normalize(), + Vec3::NEG_X, + Vec3::new(-1., 0., -1.).normalize(), + Vec3::NEG_Z, + Vec3::new(1., 0., -1.).normalize(), + ] + .map(Vec3::normalize) + .map(|v| (quat * v)); + let points = normals.map(|v| (v * curr.thickness) + Vec3::from(curr.point)); + vertex_normals.extend(normals); + vertex_positions.extend(points); + vertex_colors.extend([curr.color.to_bevy().to_srgba().to_f32_array(); 8]); + idk += 1; + } + } + let vertex_indecies = (0..idk - 1).flat_map(indecies).collect::>(); + let mut mesh = Mesh::new( + PrimitiveTopology::TriangleList, + RenderAssetUsages::RENDER_WORLD, + ); + mesh.insert_indices(Indices::U32(vertex_indecies)); + mesh.insert_attribute(Mesh::ATTRIBUTE_COLOR, vertex_colors); + mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, vertex_normals); + mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, vertex_positions); + + match lines.entity.get() { + Some(e) => cmds.entity(*e), + None => cmds.spawn(SpatialNode(Arc::downgrade(&lines.spatial))), + } + .insert(( + Mesh3d(meshes.add(mesh)), + MeshMaterial3d(materials.add(PbrMaterial { + color: Color::WHITE, + roughness: 1.0, + alpha_mode: AlphaMode::Blend, + ..default() + })), + )); + } +} + +// const BASE: [u16; 6] = [0, 8, 1, 8, 9, 1]; +const INDECIES: [u32; 48] = [ + 0, 8, 1, 8, 9, 1, 1, 9, 2, 9, 10, 2, 2, 10, 3, 10, 11, 3, 3, 11, 4, 11, 12, 4, 4, 12, 5, 12, + 13, 5, 5, 13, 6, 13, 14, 6, 6, 14, 7, 14, 15, 7, 7, 15, 0, 15, 8, 0, +]; +fn indecies(base: u32) -> [u32; INDECIES.len()] { + INDECIES.map(|v| v + (base * 8)) +} +fn cyclic_indecies(base: u32) -> [u32; INDECIES.len()] { + let mut out = INDECIES.map(|v| if v >= 8 { v + (base * 8) } else { v }); + out.reverse(); + out +} + static LINES_REGISTRY: Registry = Registry::new(); pub struct Lines { - space: Arc, + spatial: Arc, data: Mutex>, + gen_mesh: AtomicBool, + entity: OnceLock, } impl Lines { pub fn add_to(node: &Arc, lines: Vec) -> Result> { @@ -34,9 +184,12 @@ impl Lines { bounds }); + info!("line::add_to"); let lines = LINES_REGISTRY.add(Lines { - space: node.get_aspect::()?.clone(), + spatial: node.get_aspect::()?.clone(), data: Mutex::new(lines), + gen_mesh: AtomicBool::new(true), + entity: OnceLock::new(), }); node.add_aspect_raw(lines.clone()); @@ -44,7 +197,7 @@ impl Lines { } fn draw(&self, token: &MainThreadToken) { - let transform_mat = self.space.global_transform(); + let transform_mat = self.spatial.global_transform(); let data = self.data.lock().clone(); for line in &data { let mut points: VecDeque = line @@ -82,8 +235,10 @@ impl Lines { } impl LinesAspect for Lines { fn set_lines(node: Arc, _calling_client: Arc, lines: Vec) -> Result<()> { + info!("set_lines"); let lines_aspect = node.get_aspect::()?; *lines_aspect.data.lock() = lines; + lines_aspect.gen_mesh.store(true, Ordering::Relaxed); Ok(()) } } @@ -95,7 +250,7 @@ impl Drop for Lines { pub fn draw_all(token: &MainThreadToken) { for lines in LINES_REGISTRY.get_valid_contents() { - if let Some(node) = lines.space.node() { + if let Some(node) = lines.spatial.node() { if node.enabled() { lines.draw(token); } diff --git a/src/nodes/drawable/model.rs b/src/nodes/drawable/model.rs index 2671156..c042157 100644 --- a/src/nodes/drawable/model.rs +++ b/src/nodes/drawable/model.rs @@ -242,7 +242,6 @@ impl HashedPbrMaterial { hash_color(mat.emission_factor, state); state.write_u32(mat.metallic.to_bits()); state.write_u32(mat.roughness.to_bits()); - mat.use_stereokit_uvs.hash(state); match mat.alpha_mode { AlphaMode::Opaque => state.write_u8(0), AlphaMode::Mask(v) => { @@ -392,7 +391,6 @@ impl MaterialParameter { } } mat.alpha_mode = AlphaMode::AlphaToCoverage; - mat.use_stereokit_uvs = false; } } } @@ -438,7 +436,6 @@ impl Material { .as_ref() .map(|p| asset_server.load(p.as_path())), spherical_harmonics: bevy_sk::skytext::SPHERICAL_HARMONICS_HANDLE, - use_stereokit_uvs: false, } } } diff --git a/src/objects/input/sk_hand.rs b/src/objects/input/sk_hand.rs index c55a2a5..b838898 100644 --- a/src/objects/input/sk_hand.rs +++ b/src/objects/input/sk_hand.rs @@ -226,7 +226,6 @@ impl SkHand { let material = materials.add(PbrMaterial { color: Srgba::new(1.0, 1.0, 1.0, 1.0).into(), alpha_mode: AlphaMode::Blend, - use_stereokit_uvs: false, diffuse_texture: Some(GRADIENT_TEXTURE_HANDLE), roughness: 1.0, ..default()