use concinnity_core::components::Camera3D;
use concinnity_core::components::FrameInput;
use concinnity_core::ecs::PickIndex;
use concinnity_core::ecs::World;
use concinnity_core::ecs::asset_id::AssetId;
use crate::editor::asset_handle::AssetHandle;
use crate::editor::hook::EditorHook;
use crate::editor::viewport::highlight;
use crate::editor::viewport::marquee;
pub(in crate::editor::hook) struct MarqueeDrag {
anchor: [f32; 2],
current: [f32; 2],
additive: bool,
moved: bool,
}
impl EditorHook {
pub(in crate::editor::hook) fn begin_marquee(&mut self, anchor: [f32; 2], additive: bool) {
self.marquee = Some(MarqueeDrag {
anchor,
current: anchor,
additive,
moved: false,
});
}
pub(in crate::editor::hook) fn drive_marquee(
&mut self,
input: &FrameInput,
vp: [f32; 2],
world: &mut World,
) {
let Some(m) = &mut self.marquee else {
return;
};
if input.escape {
self.marquee = None;
return;
}
m.current = [input.mouse_x, input.mouse_y];
let dx = (m.current[0] - m.anchor[0]).abs();
let dy = (m.current[1] - m.anchor[1]).abs();
if dx.max(dy) >= marquee::DRAG_START_PX {
m.moved = true;
}
if input.left_button_down {
return;
}
let Some(m) = self.marquee.take() else {
return;
};
if !m.moved {
if !m.additive {
self.selection.clear();
self.pick_last = None;
}
return;
}
let rect = marquee::rect_from_corners(m.anchor, m.current);
let hits: Vec<AssetHandle> = marquee_hits(world, vp, rect, &self.locked_ids())
.into_iter()
.filter_map(|id| self.handle_of_asset_id(id))
.collect();
if m.additive {
self.selection.extend(hits);
} else {
self.selection.set(hits);
}
self.pick_last = None;
self.follow_active(world);
}
pub(in crate::editor::hook) fn drive_marquee_draw(&self, world: &mut World, shown: bool) {
match &self.marquee {
Some(m) if shown && m.moved => {
marquee::place(world, marquee::rect_from_corners(m.anchor, m.current));
}
_ => marquee::hide(world),
}
}
}
fn marquee_hits(
world: &World,
vp: [f32; 2],
rect: [f32; 4],
locked: &std::collections::BTreeSet<AssetId>,
) -> Vec<AssetId> {
let Some(index) = world.resource::<PickIndex>() else {
return Vec::new();
};
let Some(cam) = world.query::<Camera3D>().next() else {
return Vec::new();
};
let fov = cam.fov_y_degrees.to_radians();
index
.entries
.iter()
.filter_map(|e| {
let r = highlight::screen_rect(&cam.view_matrix, fov, vp, e.bb_min, e.bb_max)?;
if !marquee::rects_intersect(rect, r) {
return None;
}
(!locked.contains(&e.asset_id)).then_some(e.asset_id)
})
.collect()
}