Refactor node building logic to support recursive child attachment in bridge reification
This commit is contained in:
@@ -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);
|
let dims = glam::Vec3::from(node.dimensions);
|
||||||
if dims.length() < 0.001 {
|
if dims.length() < 0.001 {
|
||||||
eprintln!("[bridge/reify] Skipping node {} (zero dimensions)", id);
|
eprintln!("[bridge/reify] Skipping node {} (zero dimensions)", id);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 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);
|
||||||
|
|
||||||
// Try to load the appropriate model based on entity type and model URL
|
// 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 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 {
|
let entity_type_name = match node.entity_type {
|
||||||
@@ -160,18 +163,14 @@ impl Reify for BridgeState {
|
|||||||
6 => "light",
|
6 => "light",
|
||||||
_ => "unknown"
|
_ => "unknown"
|
||||||
};
|
};
|
||||||
|
|
||||||
let model_source = if !node.model_url.is_empty() {
|
let model_source = if !node.model_url.is_empty() {
|
||||||
format!("from URL: {}", node.model_url)
|
format!("from URL: {}", node.model_url)
|
||||||
} else {
|
} else {
|
||||||
format!("primitive from {}", model_path.display())
|
format!("primitive from {}", model_path.display())
|
||||||
};
|
};
|
||||||
|
|
||||||
eprintln!("[bridge/reify] Loading {} for node {} {}", entity_type_name, id, model_source);
|
eprintln!("[bridge/reify] Loading {} for node {} {}", entity_type_name, id, model_source);
|
||||||
|
|
||||||
match node.entity_type {
|
match node.entity_type {
|
||||||
4 => {
|
4 => {
|
||||||
// Text entity: use node.name as text for now
|
|
||||||
let text = ast::elements::Text::new(&node.name)
|
let text = ast::elements::Text::new(&node.name)
|
||||||
.character_height(node.dimensions[1].max(0.01))
|
.character_height(node.dimensions[1].max(0.01))
|
||||||
.color(ast::elements::RgbaLinear::new(
|
.color(ast::elements::RgbaLinear::new(
|
||||||
@@ -180,18 +179,15 @@ impl Reify for BridgeState {
|
|||||||
Some(text.build())
|
Some(text.build())
|
||||||
}
|
}
|
||||||
5 => {
|
5 => {
|
||||||
// Image entity: use PanelUI as a placeholder for now
|
|
||||||
eprintln!("[bridge/reify] Image entity type detected for node {}. Using PanelUI as placeholder.", id);
|
eprintln!("[bridge/reify] Image entity type detected for node {}. Using PanelUI as placeholder.", id);
|
||||||
let panel = ast::elements::PanelUI::default();
|
let panel = ast::elements::PanelUI::default();
|
||||||
Some(panel.build())
|
Some(panel.build())
|
||||||
}
|
}
|
||||||
6 => {
|
6 => {
|
||||||
// Light entity: use asteroids Light element
|
|
||||||
eprintln!("[bridge/reify] Light entity type detected for node {}.", id);
|
eprintln!("[bridge/reify] Light entity type detected for node {}.", id);
|
||||||
let color = ast::elements::RgbaLinear::new(
|
let color = ast::elements::RgbaLinear::new(
|
||||||
node.color[0], node.color[1], node.color[2], node.color[3]
|
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 intensity = node.dimensions.get(1).copied().unwrap_or(1.0).max(0.01);
|
||||||
let light = ast::elements::Light::new()
|
let light = ast::elements::Light::new()
|
||||||
.color(color)
|
.color(color)
|
||||||
@@ -199,7 +195,6 @@ impl Reify for BridgeState {
|
|||||||
Some(light.build())
|
Some(light.build())
|
||||||
}
|
}
|
||||||
7 => {
|
7 => {
|
||||||
// Zone entity: use asteroids Zone element
|
|
||||||
eprintln!("[bridge/reify] Zone entity type detected for node {}.", id);
|
eprintln!("[bridge/reify] Zone entity type detected for node {}.", id);
|
||||||
let color = ast::elements::RgbaLinear::new(
|
let color = ast::elements::RgbaLinear::new(
|
||||||
node.color[0], node.color[1], node.color[2], node.color[3]
|
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);
|
eprintln!("[bridge/reify] No model available for entity type {} (node {})", node.entity_type, id);
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
// Recursively build children
|
||||||
Some((*id, Spatial::default()
|
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)
|
.transform(transform)
|
||||||
.build()
|
.build()
|
||||||
.maybe_child(model_child)))
|
.maybe_child(model_child);
|
||||||
});
|
for (_cid, child_spatial) in children {
|
||||||
|
spatial = spatial.child(child_spatial);
|
||||||
PlaySpace.build().stable_children(children)
|
}
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user