feat: finish line impl and switch to bevy bounds

Signed-off-by: Schmarni <marnistromer@gmail.com>
This commit is contained in:
Schmarni
2025-06-28 11:34:09 +02:00
committed by Nova King
parent 2bf244bb6e
commit 85bb21414d
6 changed files with 142 additions and 118 deletions

View File

@@ -9,20 +9,17 @@ use crate::{
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, OnceLock,
atomic::{AtomicBool, Ordering},
render::{
mesh::{Indices, MeshAabb, PrimitiveTopology},
primitives::Aabb,
},
};
use stereokit_rust::{
maths::Bounds, sk::MainThreadToken, system::LinePoint as SkLinePoint, util::Color128,
use bevy_sk::vr_materials::PbrMaterial;
use glam::Vec3;
use parking_lot::Mutex;
use std::sync::{
Arc, OnceLock,
atomic::{AtomicBool, Ordering},
};
pub struct LinesNodePlugin;
@@ -32,16 +29,6 @@ impl Plugin for LinesNodePlugin {
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<Assets<Mesh>>,
@@ -62,25 +49,30 @@ fn build_line_mesh(
if lines_data.is_empty() {
continue;
}
let mut idk = 0;
let mut indecies_set = 0;
for line in lines_data.iter() {
let start_set = indecies_set;
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 mut end = false;
let next = match peekable.peek() {
Some(v) => Some(*v),
None => line.cyclic.then(|| line.points.first()).flatten(),
None => {
end = true;
line.cyclic.then(|| line.points.first()).flatten()
}
};
out.push((last, curr, next));
out.push((last, curr, next, end));
last = Some(curr);
}
out
};
for (last, curr, next) in optional_points {
for (last, curr, next, end) in optional_points {
let last_quat = last.map(|v| {
Quat::from_rotation_arc(
Vec3::Y,
@@ -115,10 +107,18 @@ fn build_line_mesh(
vertex_normals.extend(normals);
vertex_positions.extend(points);
vertex_colors.extend([curr.color.to_bevy().to_srgba().to_f32_array(); 8]);
idk += 1;
if !end {
vertex_indecies.extend(indecies(indecies_set));
}
indecies_set += 1;
}
if line.cyclic {
vertex_indecies.extend(cyclic_indecies(start_set, indecies_set - 1));
} else {
vertex_indecies.extend(cap_indecies(start_set, false));
vertex_indecies.extend(cap_indecies(indecies_set - 1, true));
}
}
let vertex_indecies = (0..idk - 1).flat_map(indecies).collect::<Vec<_>>();
let mut mesh = Mesh::new(
PrimitiveTopology::TriangleList,
RenderAssetUsages::RENDER_WORLD,
@@ -126,7 +126,10 @@ fn build_line_mesh(
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);
mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, vertex_positions.clone());
if let Some(aabb) = mesh.compute_aabb() {
*lines.bounds.lock() = aabb;
}
match lines.entity.get() {
Some(e) => cmds.entity(*e),
@@ -137,23 +140,38 @@ fn build_line_mesh(
MeshMaterial3d(materials.add(PbrMaterial {
color: Color::WHITE,
roughness: 1.0,
alpha_mode: AlphaMode::Blend,
alpha_mode: AlphaMode::Opaque,
..default()
})),
));
}
}
const END_CAP_INDECIES: [u32; 18] = [0, 1, 7, 7, 1, 2, 7, 2, 6, 6, 2, 3, 6, 3, 5, 5, 3, 4];
fn cap_indecies(set: u32, flip: bool) -> [u32; END_CAP_INDECIES.len()] {
let mut out = END_CAP_INDECIES.map(|v| v + (set * 8));
if flip {
out.reverse();
}
out
}
// 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 indecies(set: u32) -> [u32; INDECIES.len()] {
INDECIES.map(|v| v + (set * 8))
}
fn cyclic_indecies(base: u32) -> [u32; INDECIES.len()] {
let mut out = INDECIES.map(|v| if v >= 8 { v + (base * 8) } else { v });
fn cyclic_indecies(start_set: u32, end_set: u32) -> [u32; INDECIES.len()] {
let mut out = INDECIES.map(|v| {
if v < 8 {
v + ((start_set) * 8)
} else {
v + ((end_set - 1) * 8)
}
});
out.reverse();
out
}
@@ -165,6 +183,7 @@ pub struct Lines {
data: Mutex<Vec<Line>>,
gen_mesh: AtomicBool,
entity: OnceLock<Entity>,
bounds: Mutex<Aabb>,
}
impl Lines {
pub fn add_to(node: &Arc<Node>, lines: Vec<Line>) -> Result<Arc<Lines>> {
@@ -173,15 +192,10 @@ impl Lines {
.unwrap()
.bounding_box_calc
.set(|node| {
let mut bounds = Bounds::default();
if let Ok(lines) = node.get_aspect::<Lines>() {
for line in &*lines.data.lock() {
for point in &line.points {
bounds.grown_point(Vec3::from(point.point));
}
}
}
bounds
node.get_aspect::<Lines>()
.ok()
.map(|v| v.bounds.lock().clone())
.unwrap_or_default()
});
info!("line::add_to");
@@ -190,48 +204,12 @@ impl Lines {
data: Mutex::new(lines),
gen_mesh: AtomicBool::new(true),
entity: OnceLock::new(),
bounds: Mutex::new(Aabb::default()),
});
node.add_aspect_raw(lines.clone());
Ok(lines)
}
fn draw(&self, token: &MainThreadToken) {
let transform_mat = self.spatial.global_transform();
let data = self.data.lock().clone();
for line in &data {
let mut points: VecDeque<SkLinePoint> = line
.points
.iter()
.map(|p| SkLinePoint {
pt: transform_mat.transform_point3(Vec3::from(p.point)).into(),
thickness: p.thickness,
color: Color128::new(p.color.c.r, p.color.c.g, p.color.c.b, p.color.a).into(),
})
.collect();
if line.cyclic && !points.is_empty() {
let first = line.points.first().unwrap();
let last = line.points.last().unwrap();
let color = Color128 {
r: first.color.c.r.lerp(last.color.c.r, 0.5),
g: first.color.c.g.lerp(last.color.c.g, 0.5),
b: first.color.c.b.lerp(last.color.c.b, 0.5),
a: first.color.a.lerp(last.color.a, 0.5),
};
let connect_point = SkLinePoint {
pt: transform_mat
.transform_point3(Vec3::from(first.point).lerp(Vec3::from(last.point), 0.5))
.into(),
thickness: (first.thickness + last.thickness) * 0.5,
color: color.into(),
};
points.push_front(connect_point);
points.push_back(connect_point);
}
stereokit_rust::system::Lines::add_list(token, points.make_contiguous());
}
}
}
impl LinesAspect for Lines {
fn set_lines(node: Arc<Node>, _calling_client: Arc<Client>, lines: Vec<Line>) -> Result<()> {
@@ -247,13 +225,3 @@ impl Drop for Lines {
LINES_REGISTRY.remove(self);
}
}
pub fn draw_all(token: &MainThreadToken) {
for lines in LINES_REGISTRY.get_valid_contents() {
if let Some(node) = lines.spatial.node() {
if node.enabled() {
lines.draw(token);
}
}
}
}