use concinnity_core::components::PointLight;
use concinnity_core::components::Transform;
use concinnity_core::ecs::World;
use concinnity_core::ecs::asset_id::AssetId;
use concinnity_host::thread::asset_id;
use crate::editor::hook::tests::fixtures::{click_at, entry, hook, pick_world};
use crate::editor::hook::tests::fixtures::active;
use crate::editor::panels::registry::PanelKey;
use crate::editor::viewport::billboards;
fn billboard_world(light_pos: [f32; 3], picks: Vec<(AssetId, [f32; 3], [f32; 3])>) -> World {
let mut world = pick_world([0.0; 3], picks);
for (id, s) in billboards::sprites() {
world.push_identified(id, s);
}
let entity = world.push(PointLight {
position: light_pos,
..Default::default()
});
let id = asset_id::intern("lamp");
world.identify(entity, id);
world
}
fn lamp_entry(pos: [f32; 3]) -> serde_json::Value {
serde_json::json!({"type": "PointLight", "args": {"$id": "lamp", "position": pos}})
}
#[test]
fn billboard_click_selects_the_light_and_seeds_its_transform() {
asset_id::reset_interner();
let mut world = billboard_world([0.0, 0.0, -5.0], Vec::new());
let mut h = hook(vec![lamp_entry([0.0, 0.0, -5.0])]);
click_at(&mut world, &mut h, [640.0, 360.0]);
assert_eq!(
active(&h).as_deref(),
Some("lamp"),
"the icon press selects"
);
assert!(
!h.open[PanelKey::Assets] && !h.form_open(),
"an icon press opens no UI"
);
let entity = world
.resource::<concinnity_core::ecs::EntityById>()
.unwrap()
.iter()
.next()
.map(|(_, e)| e)
.unwrap();
let t = world.get::<Transform>(entity).unwrap();
assert_eq!(t.position, [0.0, 0.0, -5.0]);
assert!(
h.gizmo_layout(&world, [1280.0, 720.0]).is_some(),
"the translate gizmo anchors on the selected light"
);
}
#[test]
fn billboard_and_mesh_overlap_prefers_the_nearer_hit() {
asset_id::reset_interner();
let wall = asset_id::intern("wall");
let mut world = billboard_world(
[0.0, 0.0, -5.0],
vec![(wall, [-1.0, -1.0, -3.0], [1.0, 1.0, -2.0])],
);
let mut h = hook(vec![entry("wall", "Sprite"), lamp_entry([0.0, 0.0, -5.0])]);
click_at(&mut world, &mut h, [640.0, 360.0]);
assert_eq!(active(&h).as_deref(), Some("wall"), "the nearer mesh wins");
asset_id::reset_interner();
let wall = asset_id::intern("wall");
let mut world = billboard_world(
[0.0, 0.0, -5.0],
vec![(wall, [-1.0, -1.0, -10.0], [1.0, 1.0, -9.0])],
);
let mut h = hook(vec![entry("wall", "Sprite"), lamp_entry([0.0, 0.0, -5.0])]);
click_at(&mut world, &mut h, [640.0, 360.0]);
assert_eq!(active(&h).as_deref(), Some("lamp"), "the nearer icon wins");
}
#[test]
fn hidden_and_locked_billboards_follow_the_pick_rules() {
asset_id::reset_interner();
let mut world = billboard_world([0.0, 0.0, -5.0], Vec::new());
let mut h = hook(vec![lamp_entry([0.0, 0.0, -5.0])]);
h.locked_assets.insert(h.handle_for("lamp"));
click_at(&mut world, &mut h, [640.0, 360.0]);
assert_eq!(active(&h).as_deref(), None, "a locked icon is pick-through");
assert!(h.marquee.is_some(), "the click fell through to empty space");
asset_id::reset_interner();
let mut world = billboard_world([0.0, 0.0, -5.0], Vec::new());
let mut h = hook(vec![lamp_entry([0.0, 0.0, -5.0])]);
h.hidden_assets.insert(h.handle_for("lamp"));
click_at(&mut world, &mut h, [640.0, 360.0]);
assert_eq!(active(&h).as_deref(), None, "a hidden asset draws no icon");
assert!(h.marquee.is_some(), "the click fell through to empty space");
}