use crate::ecs::EditorWorld;
use nightshade::ecs::camera::commands::spawn_pan_orbit_camera_with_config;
use nightshade::ecs::camera::components::PanOrbitCamera;
use nightshade::prelude::*;
pub fn spawn_default(editor_world: &mut EditorWorld, world: &mut World) {
let camera_entity = spawn_pan_orbit_camera_with_config(
world,
"Main Camera".to_string(),
PanOrbitCamera::new(Vec3::new(0.0, 0.0, 0.0), 5.0).with_yaw_pitch(0.0, 0.3),
);
editor_world.resources.camera.camera_entity = Some(camera_entity);
world.resources.active_camera = Some(camera_entity);
editor_world
.resources
.editor_scene
.register_scaffolding(camera_entity);
}
pub fn handle_reset_input(editor_world: &mut EditorWorld, world: &mut World) {
let reset_pressed = world.resources.input.keyboard.is_key_pressed(KeyCode::KeyC);
let typing_in_text_field = world
.resources
.retained_ui
.interaction
.focused_entity
.is_some_and(|entity| {
world.ui.get_ui_text_input(entity).is_some()
|| world.ui.get_ui_text_area(entity).is_some()
|| world.ui.get_ui_drag_value(entity).is_some()
});
if reset_pressed
&& !editor_world.resources.camera.reset_camera_was_pressed
&& !typing_in_text_field
{
frame_scene(editor_world, world);
}
editor_world.resources.camera.reset_camera_was_pressed = reset_pressed;
}
pub fn focus_point(editor_world: &EditorWorld, world: &World) -> Vec3 {
let Some(camera_entity) = editor_world.resources.camera.camera_entity else {
return Vec3::zeros();
};
world
.core
.get_pan_orbit_camera(camera_entity)
.map(|orbit| orbit.target_focus)
.unwrap_or_else(Vec3::zeros)
}
pub fn frame_scene(editor_world: &mut EditorWorld, world: &mut World) {
let roots = editor_world.resources.loading.model_entities.clone();
frame_entities(editor_world, world, &roots);
}
pub fn frame_entities(editor_world: &mut EditorWorld, world: &mut World, roots: &[Entity]) {
let Some(camera_entity) = editor_world.resources.camera.camera_entity else {
return;
};
let mut min = Vec3::new(f32::INFINITY, f32::INFINITY, f32::INFINITY);
let mut max = Vec3::new(f32::NEG_INFINITY, f32::NEG_INFINITY, f32::NEG_INFINITY);
let mut found_any = false;
for &root in roots {
accumulate_bounds(world, root, &mut min, &mut max, &mut found_any);
for descendant in nightshade::ecs::transform::queries::query_descendants(world, root) {
accumulate_bounds(world, descendant, &mut min, &mut max, &mut found_any);
}
}
let fov_rad = world
.core
.get_camera(camera_entity)
.and_then(|camera| match camera.projection {
nightshade::ecs::camera::components::Projection::Perspective(perspective) => {
Some(perspective.y_fov_rad)
}
_ => None,
})
.unwrap_or(45.0_f32.to_radians());
let (center, radius, half_diagonal) = if found_any {
let center = (min + max) * 0.5;
let half_diagonal = ((max - min) * 0.5).norm().max(0.001);
(
center,
half_diagonal / (fov_rad * 0.5).sin() * 1.2,
half_diagonal,
)
} else {
(Vec3::zeros(), 5.0, 1.0)
};
if let Some(camera) = world.core.get_camera_mut(camera_entity)
&& let nightshade::ecs::camera::components::Projection::Perspective(perspective) =
&mut camera.projection
{
perspective.z_near = (half_diagonal * 0.001).clamp(0.001, 0.1);
}
if let Some(pan_orbit) = world.core.get_pan_orbit_camera_mut(camera_entity) {
pan_orbit.target_focus = center;
pan_orbit.target_radius = radius;
pan_orbit.target_yaw = 0.0;
pan_orbit.target_pitch = 0.3;
pan_orbit.limits.zoom_lower = half_diagonal * 0.001;
pan_orbit.pan_distance = Some(radius);
}
}
fn accumulate_bounds(
world: &World,
entity: Entity,
min: &mut Vec3,
max: &mut Vec3,
found_any: &mut bool,
) {
let Some(bounding_volume) = world.core.get_bounding_volume(entity) else {
return;
};
let Some(global_transform) = world.core.get_global_transform(entity) else {
return;
};
let world_obb = bounding_volume.obb.transform(&global_transform.0);
for corner in world_obb.get_corners() {
min.x = min.x.min(corner.x);
min.y = min.y.min(corner.y);
min.z = min.z.min(corner.z);
max.x = max.x.max(corner.x);
max.y = max.y.max(corner.y);
max.z = max.z.max(corner.z);
*found_any = true;
}
}