feat: enhance model loading in reify function with entity type support
This commit is contained in:
@@ -11,7 +11,7 @@ use stardust_xr_asteroids as ast; // alias for brevity
|
|||||||
use stardust_xr_asteroids::{
|
use stardust_xr_asteroids::{
|
||||||
client::ClientState,
|
client::ClientState,
|
||||||
elements::{PlaySpace, Spatial, Model},
|
elements::{PlaySpace, Spatial, Model},
|
||||||
Migrate, Reify, CustomElement, Projector, Context,
|
Migrate, Reify, CustomElement, Projector, Context, Transformable,
|
||||||
};
|
};
|
||||||
use stardust_xr_molecules::accent_color::AccentColor;
|
use stardust_xr_molecules::accent_color::AccentColor;
|
||||||
use stardust_xr_fusion::objects::connect_client as fusion_connect_client;
|
use stardust_xr_fusion::objects::connect_client as fusion_connect_client;
|
||||||
@@ -70,89 +70,25 @@ impl ClientState for BridgeState {
|
|||||||
|
|
||||||
impl Reify for BridgeState {
|
impl Reify for BridgeState {
|
||||||
fn reify(&self) -> impl ast::Element<Self> {
|
fn reify(&self) -> impl ast::Element<Self> {
|
||||||
use stardust_xr_fusion::values::{color, Vector3};
|
use stardust_xr_fusion::values::color;
|
||||||
use stardust_xr_fusion::drawable::{Line, LinePoint};
|
|
||||||
|
|
||||||
eprintln!("[bridge/reify] Reifying {} nodes", self.nodes.len());
|
eprintln!("[bridge/reify] Reifying {} nodes", self.nodes.len());
|
||||||
|
|
||||||
fn create_wireframe_cube(color_val: stardust_xr_fusion::values::Color, thickness: f32) -> Vec<Line> {
|
fn get_model_path(entity_type: u8) -> Option<PathBuf> {
|
||||||
let h = 0.5; // half size
|
let cache_dir = dirs::cache_dir()?.join("starworld/primitives");
|
||||||
let points = [
|
let filename = match entity_type {
|
||||||
[-h, -h, -h], [h, -h, -h], [h, h, -h], [-h, h, -h], // back face
|
1 => "cube.glb", // Box
|
||||||
[-h, -h, h], [h, -h, h], [h, h, h], [-h, h, h], // front face
|
2 => "sphere.glb", // Sphere
|
||||||
];
|
3 => "model.glb", // Model (using Suzanne as placeholder)
|
||||||
|
_ => return None,
|
||||||
// 12 edges of the cube
|
};
|
||||||
let edges = [
|
let path = cache_dir.join(filename);
|
||||||
(0, 1), (1, 2), (2, 3), (3, 0), // back face
|
if path.exists() {
|
||||||
(4, 5), (5, 6), (6, 7), (7, 4), // front face
|
Some(path)
|
||||||
(0, 4), (1, 5), (2, 6), (3, 7), // connecting edges
|
} else {
|
||||||
];
|
eprintln!("[bridge/reify] Model file not found: {}", path.display());
|
||||||
|
None
|
||||||
edges.iter().map(|(a, b)| {
|
|
||||||
let pa = points[*a];
|
|
||||||
let pb = points[*b];
|
|
||||||
Line {
|
|
||||||
points: vec![
|
|
||||||
LinePoint { point: Vector3 { x: pa[0], y: pa[1], z: pa[2] }, thickness, color: color_val },
|
|
||||||
LinePoint { point: Vector3 { x: pb[0], y: pb[1], z: pb[2] }, thickness, color: color_val },
|
|
||||||
],
|
|
||||||
cyclic: false,
|
|
||||||
}
|
|
||||||
}).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_wireframe_sphere(color_val: stardust_xr_fusion::values::Color, thickness: f32) -> Vec<Line> {
|
|
||||||
let segments = 32;
|
|
||||||
let r = 0.5; // radius
|
|
||||||
let mut lines = Vec::new();
|
|
||||||
|
|
||||||
// Create 3 orthogonal circles (XY, XZ, YZ planes)
|
|
||||||
for axis in 0..3 {
|
|
||||||
let mut points = Vec::new();
|
|
||||||
for i in 0..segments { // Changed from 0..=segments to avoid duplicate at 0 and segments
|
|
||||||
let angle = (i as f32 / segments as f32) * std::f32::consts::TAU;
|
|
||||||
let (sin, cos) = angle.sin_cos();
|
|
||||||
let point = match axis {
|
|
||||||
0 => Vector3 { x: cos * r, y: sin * r, z: 0.0 }, // XY plane
|
|
||||||
1 => Vector3 { x: cos * r, y: 0.0, z: sin * r }, // XZ plane
|
|
||||||
_ => Vector3 { x: 0.0, y: cos * r, z: sin * r }, // YZ plane
|
|
||||||
};
|
|
||||||
points.push(LinePoint { point, thickness, color: color_val });
|
|
||||||
}
|
|
||||||
lines.push(Line { points, cyclic: true });
|
|
||||||
}
|
}
|
||||||
lines
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_octahedron_wireframe(color_val: stardust_xr_fusion::values::Color, thickness: f32) -> Vec<Line> {
|
|
||||||
let r = 0.5;
|
|
||||||
// 6 vertices of octahedron
|
|
||||||
let verts = [
|
|
||||||
Vector3 { x: 0.0, y: r, z: 0.0 }, // top
|
|
||||||
Vector3 { x: r, y: 0.0, z: 0.0 }, // +X
|
|
||||||
Vector3 { x: 0.0, y: 0.0, z: r }, // +Z
|
|
||||||
Vector3 { x: -r, y: 0.0, z: 0.0 }, // -X
|
|
||||||
Vector3 { x: 0.0, y: 0.0, z: -r }, // -Z
|
|
||||||
Vector3 { x: 0.0, y: -r, z: 0.0 }, // bottom
|
|
||||||
];
|
|
||||||
|
|
||||||
// 12 edges
|
|
||||||
let edges = [
|
|
||||||
(0, 1), (0, 2), (0, 3), (0, 4), // top pyramid
|
|
||||||
(5, 1), (5, 2), (5, 3), (5, 4), // bottom pyramid
|
|
||||||
(1, 2), (2, 3), (3, 4), (4, 1), // equator
|
|
||||||
];
|
|
||||||
|
|
||||||
edges.iter().map(|(a, b)| {
|
|
||||||
Line {
|
|
||||||
points: vec![
|
|
||||||
LinePoint { point: verts[*a], thickness, color: color_val },
|
|
||||||
LinePoint { point: verts[*b], thickness, color: color_val },
|
|
||||||
],
|
|
||||||
cyclic: false,
|
|
||||||
}
|
|
||||||
}).collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let children = self.nodes.iter().filter_map(|(id, node)| {
|
let children = self.nodes.iter().filter_map(|(id, node)| {
|
||||||
@@ -164,62 +100,43 @@ impl Reify for BridgeState {
|
|||||||
|
|
||||||
let (scale, rot, trans) = node.transform.to_scale_rotation_translation();
|
let (scale, rot, trans) = node.transform.to_scale_rotation_translation();
|
||||||
let vis_scale = if dims.length() > 0.001 { dims } else { scale };
|
let vis_scale = if dims.length() > 0.001 { dims } else { scale };
|
||||||
let node_color = color::rgba_linear!(node.color[0], node.color[1], node.color[2], node.color[3]);
|
|
||||||
|
|
||||||
let trans_array = [trans.x, trans.y, trans.z];
|
let trans_array = [trans.x, trans.y, trans.z];
|
||||||
let rot_array = [rot.x, rot.y, rot.z, rot.w];
|
let rot_array = [rot.x, rot.y, rot.z, rot.w];
|
||||||
let scale_array = [vis_scale.x, vis_scale.y, vis_scale.z];
|
let scale_array = [vis_scale.x, vis_scale.y, vis_scale.z];
|
||||||
let transform = stardust_xr_fusion::spatial::Transform::from_translation_rotation_scale(trans_array, rot_array, scale_array);
|
let transform = stardust_xr_fusion::spatial::Transform::from_translation_rotation_scale(trans_array, rot_array, scale_array);
|
||||||
|
|
||||||
// Create appropriate visual based on entity type
|
// Try to load the appropriate model based on entity type
|
||||||
match node.entity_type {
|
if let Some(model_path) = get_model_path(node.entity_type) {
|
||||||
1 => {
|
eprintln!("[bridge/reify] Loading {} model for node {} from {}",
|
||||||
// Box - use wireframe cube with color
|
match node.entity_type {
|
||||||
eprintln!("[bridge/reify] Creating box (wireframe) for node {}", id);
|
1 => "cube",
|
||||||
let cube_lines = create_wireframe_cube(node_color, 0.005);
|
2 => "sphere",
|
||||||
Some((*id, Spatial::default()
|
3 => "3D model",
|
||||||
.transform(transform)
|
_ => "unknown"
|
||||||
.build()
|
}, id, model_path.display());
|
||||||
.child(Lines::new(cube_lines).build())))
|
|
||||||
}
|
match Model::direct(&model_path) {
|
||||||
2 => {
|
Ok(model) => {
|
||||||
// Sphere - use wireframe sphere with color
|
|
||||||
eprintln!("[bridge/reify] Creating sphere (wireframe) for node {}", id);
|
|
||||||
let sphere_lines = create_wireframe_sphere(node_color, 0.005);
|
|
||||||
Some((*id, Spatial::default()
|
|
||||||
.transform(transform)
|
|
||||||
.build()
|
|
||||||
.child(Lines::new(sphere_lines).build())))
|
|
||||||
}
|
|
||||||
3 => {
|
|
||||||
// Model - attempt to load from URL if provided, fallback to wireframe
|
|
||||||
if !node.model_url.is_empty() {
|
|
||||||
eprintln!("[bridge/reify] Creating model for node {} from URL: {}", id, node.model_url);
|
|
||||||
// For now, we can't easily load arbitrary HTTP URLs in the Overte format
|
|
||||||
// Fall back to wireframe octahedron as a distinct placeholder
|
|
||||||
let oct_lines = create_octahedron_wireframe(node_color, 0.005);
|
|
||||||
Some((*id, Spatial::default()
|
Some((*id, Spatial::default()
|
||||||
.transform(transform)
|
.transform(transform)
|
||||||
.build()
|
.build()
|
||||||
.child(Lines::new(oct_lines).build())))
|
.child(model.build())))
|
||||||
} else {
|
}
|
||||||
eprintln!("[bridge/reify] Creating model placeholder for node {} (no URL)", id);
|
Err(e) => {
|
||||||
let oct_lines = create_octahedron_wireframe(node_color, 0.005);
|
eprintln!("[bridge/reify] Failed to load model for node {}: {}", id, e);
|
||||||
|
// Fall back to spatial-only node
|
||||||
Some((*id, Spatial::default()
|
Some((*id, Spatial::default()
|
||||||
.transform(transform)
|
.transform(transform)
|
||||||
.build()
|
.build()))
|
||||||
.child(Lines::new(oct_lines).build())))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
} else {
|
||||||
// Unknown or unsupported type - render as wireframe cube
|
eprintln!("[bridge/reify] No model available for entity type {} (node {})", node.entity_type, id);
|
||||||
eprintln!("[bridge/reify] Creating wireframe for unknown node {} type={}", id, node.entity_type);
|
// Fallback to empty spatial
|
||||||
let cube_lines = create_wireframe_cube(node_color, 0.003);
|
Some((*id, Spatial::default()
|
||||||
Some((*id, Spatial::default()
|
.transform(transform)
|
||||||
.transform(transform)
|
.build()))
|
||||||
.build()
|
|
||||||
.child(Lines::new(cube_lines).build())))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user