use super::context::EditorContext;
use super::input::{is_ctrl_pressed, is_shift_pressed};
use crate::prelude::*;
pub fn is_editor_utility_entity(
world: &World,
entity: Entity,
camera_entity: Option<Entity>,
gizmo: Option<&crate::ecs::gizmos::GizmoState>,
) -> bool {
if Some(entity) == camera_entity {
return true;
}
if let Some(gizmo) = gizmo
&& crate::ecs::gizmos::is_gizmo_entity(world, gizmo, entity)
{
return true;
}
false
}
pub fn draw_marquee_selection(marquee: &super::context::MarqueeState, ui_context: &egui::Context) {
if let Some(rect) = marquee.rect() {
let painter = ui_context.layer_painter(egui::LayerId::new(
egui::Order::Foreground,
egui::Id::new("marquee_selection"),
));
painter.rect_filled(
rect,
0.0,
egui::Color32::from_rgba_unmultiplied(100, 150, 250, 50),
);
painter.rect_stroke(
rect,
0.0,
egui::Stroke::new(1.0, egui::Color32::from_rgb(100, 150, 250)),
egui::StrokeKind::Inside,
);
}
}
pub fn update_marquee_selection(context: &mut EditorContext, world: &mut World) {
if !super::camera_controls::is_mouse_in_selected_viewport(world) {
context.marquee.cancel();
return;
}
if context.gizmo_interaction.is_dragging() {
context.marquee.cancel();
return;
}
let in_modal_transform =
context.transform_edit.modal.operation != super::context::TransformOperation::None;
if in_modal_transform {
context.marquee.cancel();
return;
}
if world.resources.user_interface.hud_wants_pointer {
context.marquee.cancel();
return;
}
let mouse = &world.resources.input.mouse;
let mouse_pos = Vec2::new(mouse.position.x, mouse.position.y);
if mouse.state.contains(MouseState::LEFT_JUST_PRESSED)
&& context.gizmo_interaction.hover_axis.is_none()
{
context.marquee.start(egui::pos2(mouse_pos.x, mouse_pos.y));
}
if context.marquee.active {
context.marquee.update(egui::pos2(mouse_pos.x, mouse_pos.y));
if mouse.state.contains(MouseState::LEFT_JUST_RELEASED)
&& let Some(rect) = context.marquee.finish()
{
let min = Vec2::new(rect.min.x, rect.min.y);
let max = Vec2::new(rect.max.x, rect.max.y);
let min_threshold = 5.0;
if (max.x - min.x).abs() > min_threshold && (max.y - min.y).abs() > min_threshold {
select_entities_in_marquee(context, world, min, max);
}
}
}
}
fn select_entities_in_marquee(
context: &mut EditorContext,
world: &mut World,
screen_min: Vec2,
screen_max: Vec2,
) {
use crate::ecs::camera::queries::query_active_camera_matrices;
let Some(camera_matrices) = query_active_camera_matrices(world) else {
return;
};
let viewport_size = match world.resources.window.cached_viewport_size {
Some((width, height)) => (width as f32, height as f32),
None => return,
};
let viewport_rect = world.resources.window.active_viewport_rect.as_ref();
if !is_shift_pressed(world) {
context.selection.clear();
}
let view_projection = camera_matrices.projection * camera_matrices.view;
let camera_entity = world.resources.active_camera;
let gizmo = context.gizmo_interaction.active.as_ref();
let entities: Vec<Entity> = world
.query_entities(crate::ecs::GLOBAL_TRANSFORM)
.filter(|entity| !is_editor_utility_entity(world, *entity, camera_entity, gizmo))
.collect();
for entity in entities {
if let Some(global_transform) = world.get_global_transform(entity) {
let world_pos = global_transform.translation();
let clip_pos =
view_projection * nalgebra_glm::vec4(world_pos.x, world_pos.y, world_pos.z, 1.0);
if clip_pos.w <= 0.0 {
continue;
}
let ndc = nalgebra_glm::vec3(
clip_pos.x / clip_pos.w,
clip_pos.y / clip_pos.w,
clip_pos.z / clip_pos.w,
);
if ndc.x < -1.0
|| ndc.x > 1.0
|| ndc.y < -1.0
|| ndc.y > 1.0
|| ndc.z < 0.0
|| ndc.z > 1.0
{
continue;
}
let mut screen_x = (ndc.x + 1.0) * 0.5 * viewport_size.0;
let mut screen_y = (1.0 - ndc.y) * 0.5 * viewport_size.1;
if let Some(rect) = viewport_rect {
screen_x = rect.x + screen_x * (rect.width / viewport_size.0);
screen_y = rect.y + screen_y * (rect.height / viewport_size.1);
}
if screen_x >= screen_min.x
&& screen_x <= screen_max.x
&& screen_y >= screen_min.y
&& screen_y <= screen_max.y
{
context.selection.add(entity);
}
}
}
world.resources.graphics.bounding_volume_selected_entity = context.selection.primary();
}
pub fn update_picking(context: &mut EditorContext, world: &mut World) {
if !super::camera_controls::is_mouse_in_selected_viewport(world) {
return;
}
if context.gizmo_interaction.is_dragging() {
return;
}
let mouse = &world.resources.input.mouse;
let mouse_pos = mouse.position;
if mouse.state.contains(MouseState::LEFT_JUST_PRESSED)
&& !world.resources.user_interface.hud_wants_pointer
&& context.gizmo_interaction.hover_axis.is_none()
{
let pick_pos = if let Some(viewport_rect) = &world.resources.window.active_viewport_rect
&& let Some((window_width, window_height)) = world.resources.window.cached_viewport_size
{
let local = viewport_rect.to_local(mouse_pos);
let scale_x = window_width as f32 / viewport_rect.width;
let scale_y = window_height as f32 / viewport_rect.height;
((local.x * scale_x) as u32, (local.y * scale_y) as u32)
} else {
(mouse_pos.x as u32, mouse_pos.y as u32)
};
world
.resources
.gpu_picking
.request_pick(pick_pos.0, pick_pos.1);
}
if let Some(result) = world.resources.gpu_picking.take_result() {
let shift_pressed = is_shift_pressed(world);
let ctrl_pressed = is_ctrl_pressed(world);
if let Some(entity_id) = result.entity_id {
let camera_entity = world.resources.active_camera;
let gizmo = context.gizmo_interaction.active.as_ref();
let found_entity = world
.query_entities(crate::ecs::RENDER_MESH | crate::ecs::GLOBAL_TRANSFORM)
.find(|entity| {
entity.id == entity_id
&& !is_editor_utility_entity(world, *entity, camera_entity, gizmo)
});
if let Some(entity) = found_entity {
if ctrl_pressed {
context.selection.toggle(entity);
} else if shift_pressed {
context.selection.add(entity);
} else {
context.selection.set_single(entity);
}
} else if !shift_pressed && !ctrl_pressed {
context.selection.clear();
}
world.resources.graphics.bounding_volume_selected_entity = context.selection.primary();
} else if !shift_pressed && !ctrl_pressed {
context.selection.clear();
world.resources.graphics.bounding_volume_selected_entity = None;
}
}
}
pub fn check_context_menu_trigger(context: &EditorContext, world: &World) -> Option<Vec2> {
if !super::camera_controls::is_mouse_in_selected_viewport(world) {
return None;
}
if context.selection.is_empty() {
return None;
}
let in_modal_transform =
context.transform_edit.modal.operation != super::context::TransformOperation::None;
if in_modal_transform {
return None;
}
if context.gizmo_interaction.is_dragging() {
return None;
}
let mouse = &world.resources.input.mouse;
if mouse
.state
.contains(crate::prelude::MouseState::RIGHT_JUST_PRESSED)
{
return Some(mouse.position);
}
None
}