Refactor node building logic to support recursive child attachment in bridge reification

This commit is contained in:
MayaTheShy
2025-11-16 22:10:14 -05:00
parent bcdbd11c7c
commit 6d952d7569

View File

@@ -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<u64, Node>,
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)
}
}