use nightshade::ecs::transform::queries::query_descendants;
use nightshade::ecs::world::{GLOBAL_TRANSFORM, LOCAL_TRANSFORM};
use nightshade::prelude::*;
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
pub fn name(world: &World, entity: Entity) -> String {
world
.core
.get_name(entity)
.map(|name| name.0.clone())
.filter(|name| !name.is_empty())
.unwrap_or_else(|| format!("Entity {}", entity.id))
}
pub fn set_name(world: &mut World, entity: Entity, name: &str) {
world.core.set_name(entity, Name(name.to_string()));
}
pub fn children(world: &World, entity: Entity) -> Vec<Entity> {
let mut found: Vec<Entity> = Vec::new();
world
.core
.query()
.with(LOCAL_TRANSFORM)
.iter(|candidate, _, _| {
if world.core.get_parent(candidate).and_then(|parent| parent.0) == Some(entity) {
found.push(candidate);
}
});
found.sort_by_key(|entity| entity.id);
found
}
pub fn descendants(world: &World, entity: Entity) -> Vec<Entity> {
query_descendants(world, entity)
}
pub fn roots(world: &World) -> Vec<Entity> {
let mut found: Vec<Entity> = Vec::new();
world
.core
.query()
.with(LOCAL_TRANSFORM | GLOBAL_TRANSFORM)
.iter(|entity, _, _| {
if world
.core
.get_parent(entity)
.and_then(|parent| parent.0)
.is_none()
{
found.push(entity);
}
});
found.sort_by_key(|entity| entity.id);
found
}
#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub struct SceneRow {
pub id: u32,
pub name: String,
pub depth: u32,
pub has_children: bool,
pub camera: bool,
pub light: bool,
pub mesh: bool,
}
pub fn scene_tree(world: &World) -> Vec<SceneRow> {
let mut all: HashSet<Entity> = HashSet::new();
world
.core
.query()
.with(LOCAL_TRANSFORM | GLOBAL_TRANSFORM)
.iter(|entity, _, _| {
all.insert(entity);
});
let mut children_map: HashMap<Entity, Vec<Entity>> = HashMap::new();
let mut root_entities: Vec<Entity> = Vec::new();
for &entity in &all {
let parent = world
.core
.get_parent(entity)
.and_then(|parent| parent.0)
.filter(|parent| all.contains(parent));
match parent {
Some(parent) => children_map.entry(parent).or_default().push(entity),
None => root_entities.push(entity),
}
}
root_entities.sort_by_key(|entity| entity.id);
for list in children_map.values_mut() {
list.sort_by_key(|entity| entity.id);
}
let mut rows = Vec::new();
let mut visited: HashSet<Entity> = HashSet::new();
let mut stack: Vec<(Entity, u32)> = root_entities
.iter()
.rev()
.map(|entity| (*entity, 0))
.collect();
while let Some((entity, depth)) = stack.pop() {
if !visited.insert(entity) {
continue;
}
let has_children = children_map
.get(&entity)
.is_some_and(|list| !list.is_empty());
rows.push(SceneRow {
id: entity.id,
name: name(world, entity),
depth,
has_children,
camera: world.core.entity_has_camera(entity),
light: world.core.entity_has_light(entity),
mesh: world.core.entity_has_render_mesh(entity),
});
if let Some(list) = children_map.get(&entity) {
for child in list.iter().rev() {
if !visited.contains(child) {
stack.push((*child, depth + 1));
}
}
}
}
rows
}