From 6d952d756918922e56ff6839dac2b49f56777ec2 Mon Sep 17 00:00:00 2001 From: MayaTheShy Date: Sun, 16 Nov 2025 22:10:14 -0500 Subject: [PATCH] Refactor node building logic to support recursive child attachment in bridge reification --- bridge/src/lib.rs | 47 +++++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/bridge/src/lib.rs b/bridge/src/lib.rs index 6764a0d..5c626eb 100644 --- a/bridge/src/lib.rs +++ b/bridge/src/lib.rs @@ -134,21 +134,24 @@ impl Reify for BridgeState { } } - let children = self.nodes.iter().filter_map(|(id, node)| { + // Helper to recursively build a node and its children + fn build_node( + id: u64, + nodes: &HashMap, + downloader: &ModelDownloader, + ) -> Option<(u64, ast::elements::Spatial)> { + let node = nodes.get(&id)?; let dims = glam::Vec3::from(node.dimensions); if dims.length() < 0.001 { eprintln!("[bridge/reify] Skipping node {} (zero dimensions)", id); return None; } - let (scale, rot, trans) = node.transform.to_scale_rotation_translation(); let vis_scale = if dims.length() > 0.001 { dims } else { scale }; - let trans_array = [trans.x, trans.y, trans.z]; let rot_array = [rot.x, rot.y, rot.z, rot.w]; 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); - // Try to load the appropriate model based on entity type and model URL let model_child = if let Some(model_path) = get_model_path(node.entity_type, &node.model_url, downloader) { let entity_type_name = match node.entity_type { @@ -160,18 +163,14 @@ impl Reify for BridgeState { 6 => "light", _ => "unknown" }; - let model_source = if !node.model_url.is_empty() { format!("from URL: {}", node.model_url) } else { format!("primitive from {}", model_path.display()) }; - eprintln!("[bridge/reify] Loading {} for node {} {}", entity_type_name, id, model_source); - match node.entity_type { 4 => { - // Text entity: use node.name as text for now let text = ast::elements::Text::new(&node.name) .character_height(node.dimensions[1].max(0.01)) .color(ast::elements::RgbaLinear::new( @@ -180,18 +179,15 @@ impl Reify for BridgeState { Some(text.build()) } 5 => { - // Image entity: use PanelUI as a placeholder for now eprintln!("[bridge/reify] Image entity type detected for node {}. Using PanelUI as placeholder.", id); let panel = ast::elements::PanelUI::default(); Some(panel.build()) } 6 => { - // Light entity: use asteroids Light element eprintln!("[bridge/reify] Light entity type detected for node {}.", id); let color = ast::elements::RgbaLinear::new( node.color[0], node.color[1], node.color[2], node.color[3] ); - // Use y dimension as intensity if available, else default to 1.0 let intensity = node.dimensions.get(1).copied().unwrap_or(1.0).max(0.01); let light = ast::elements::Light::new() .color(color) @@ -199,7 +195,6 @@ impl Reify for BridgeState { Some(light.build()) } 7 => { - // Zone entity: use asteroids Zone element eprintln!("[bridge/reify] Zone entity type detected for node {}.", id); let color = ast::elements::RgbaLinear::new( node.color[0], node.color[1], node.color[2], node.color[3] @@ -238,14 +233,30 @@ impl Reify for BridgeState { eprintln!("[bridge/reify] No model available for entity type {} (node {})", node.entity_type, id); None }; - - Some((*id, Spatial::default() + // Recursively build children + let children: Vec<_> = nodes.iter() + .filter_map(|(child_id, child_node)| { + if child_node.parent == Some(id) { + build_node(*child_id, nodes, downloader) + } else { + None + } + }) + .collect(); + let mut spatial = Spatial::default() .transform(transform) .build() - .maybe_child(model_child))) - }); - - PlaySpace.build().stable_children(children) + .maybe_child(model_child); + for (_cid, child_spatial) in children { + spatial = spatial.child(child_spatial); + } + Some((id, spatial)) + } + // Only attach root nodes (no parent) to PlaySpace + let root_nodes: Vec<_> = self.nodes.iter() + .filter_map(|(id, node)| if node.parent.is_none() { build_node(*id, &self.nodes, downloader) } else { None }) + .collect(); + PlaySpace.build().stable_children(root_nodes) } }