use std::ops::DerefMut;
use crate::{OgleCam, OgleMode, OgleTarget};
use bevy::{
input::mouse::{MouseScrollUnit, MouseWheel},
prelude::*,
window::PrimaryWindow,
};
use dolly::prelude::*;
pub fn do_follow_target(query_transform: Query<&Transform>, mut query_cam: Query<&mut OgleCam>) {
for mut cam in query_cam.iter_mut() {
if !matches!(cam.mode, OgleMode::Normal | OgleMode::MoveOnly) {
return;
}
let prev_z = cam.rig.driver::<Position>().position.z;
match cam.target {
OgleTarget::Position(pos) => {
cam.rig.driver_mut::<Position>().position = mint::Point3 {
x: pos.x,
y: pos.y,
z: prev_z,
}
}
OgleTarget::Entity(entity) => {
if let Ok(transform) = query_transform.get(entity) {
cam.rig.driver_mut::<Position>().position = mint::Point3 {
x: transform.translation.x,
y: transform.translation.y,
z: prev_z,
};
}
}
OgleTarget::EntityWithOffset((entity, offset)) => {
if let Ok(transform) = query_transform.get(entity) {
cam.rig.driver_mut::<Position>().position = mint::Point3 {
x: transform.translation.x + offset.x,
y: transform.translation.y + offset.y,
z: prev_z,
};
}
}
OgleTarget::None => {}
}
}
}
pub fn do_camera_zooming(
mut query_cam: Query<&mut OgleCam>,
mut scroll_events: MessageReader<MouseWheel>,
) {
for mut cam in query_cam.iter_mut() {
match cam.mode {
OgleMode::Pancam | OgleMode::Normal | OgleMode::ZoomOnly => {}
OgleMode::Frozen | OgleMode::MoveOnly => return,
};
let scroll_amount = scroll_events
.read()
.map(|ev| match ev.unit {
MouseScrollUnit::Pixel => ev.y,
MouseScrollUnit::Line => ev.y * cam.settings.zoom_sensitivity,
})
.sum::<f32>();
if scroll_amount != 0. {
cam.rig.driver_mut::<Position>().position.z *= 1.0 - scroll_amount * 0.001;
}
}
}
pub fn do_pancam_movement(
primary_window: Query<&Window, With<PrimaryWindow>>,
mouse_buttons: Res<ButtonInput<MouseButton>>,
keyboard_buttons: Res<ButtonInput<KeyCode>>,
mut query_cam: Query<(&mut OgleCam, &mut Transform, &Projection)>,
mut last_pos: Local<Option<Vec2>>,
time: Res<Time>,
) {
let Ok(window) = primary_window.single() else {
return;
};
let current_pos = match window.cursor_position() {
Some(c) => Vec2::new(c.x, -c.y),
None => return,
};
let delta_device_pixels = current_pos - last_pos.unwrap_or(current_pos);
for (mut ogle_cam, transform, projection) in query_cam.iter_mut() {
if ogle_cam.mode != OgleMode::Pancam {
continue;
}
let Projection::Orthographic(projection) = projection else {
continue;
};
let mouse_delta = if !ogle_cam
.settings
.pancam
.grab_buttons
.iter()
.any(|btn| mouse_buttons.pressed(*btn) && !mouse_buttons.just_pressed(*btn))
{
Vec2::ZERO
} else {
delta_device_pixels * projection.scale
};
let keyboard_direction = {
let mut direction = Vec2::ZERO;
if ogle_cam
.settings
.pancam
.left_keys
.iter()
.any(|key| keyboard_buttons.pressed(*key))
{
direction.x -= 1.;
}
if ogle_cam
.settings
.pancam
.right_keys
.iter()
.any(|key| keyboard_buttons.pressed(*key))
{
direction.x += 1.;
}
if ogle_cam
.settings
.pancam
.up_keys
.iter()
.any(|key| keyboard_buttons.pressed(*key))
{
direction.y += 1.;
}
if ogle_cam
.settings
.pancam
.down_keys
.iter()
.any(|key| keyboard_buttons.pressed(*key))
{
direction.y -= 1.;
}
direction
};
let keyboard_delta = time.delta_secs()
* keyboard_direction.normalize_or_zero()
* ogle_cam.settings.pancam.keyboard_speed
* projection.scale;
let delta = mouse_delta - keyboard_delta;
if delta == Vec2::ZERO {
continue;
}
let new_pos = transform.translation.truncate() - delta;
ogle_cam.rig.driver_mut::<Position>().position.x = new_pos.x;
ogle_cam.rig.driver_mut::<Position>().position.y = new_pos.y;
}
*last_pos = Some(current_pos);
}
pub fn correct_to_camera_bounding(
primary_window: Query<&Window, With<PrimaryWindow>>,
mut query_cam: Query<(&mut OgleCam, &Camera, &Projection)>,
) {
let Ok(window) = primary_window.single() else {
return;
};
let window_size = window.size();
for (mut cam, camera, projection) in query_cam.iter_mut() {
if !cam.settings.bounds.enabled {
continue;
}
let Projection::Orthographic(_projection) = projection else {
continue;
};
let bounds_width = cam.settings.bounds.max_x - cam.settings.bounds.min_x;
let bounds_height = cam.settings.bounds.max_y - cam.settings.bounds.min_y;
let viewport_size = camera.logical_viewport_size().unwrap_or(window_size);
let scale_to_fit_width = bounds_width / viewport_size.x;
let scale_to_fit_height = bounds_height / viewport_size.y;
let scale_to_fit_bounds = scale_to_fit_width.min(scale_to_fit_height);
let max_allowed_scale = cam.settings.bounds.max_scale.min(scale_to_fit_bounds);
let effective_min_scale = cam.settings.bounds.min_scale.min(scale_to_fit_bounds);
let scale_range = effective_min_scale..=max_allowed_scale;
cam.rig.driver_mut::<Position>().position.z = cam
.rig
.driver::<Position>()
.position
.z
.clamp(*scale_range.start(), *scale_range.end());
let current_scale = cam.rig.driver::<Position>().position.z;
let world_viewport_width = viewport_size.x * current_scale;
let world_viewport_height = viewport_size.y * current_scale;
let half_width = world_viewport_width * 0.5;
let half_height = world_viewport_height * 0.5;
let effective_min_x = cam.settings.bounds.min_x + half_width;
let effective_max_x = cam.settings.bounds.max_x - half_width;
let effective_min_y = cam.settings.bounds.min_y + half_height;
let effective_max_y = cam.settings.bounds.max_y - half_height;
if effective_min_x <= effective_max_x {
cam.rig.driver_mut::<Position>().position.x = cam
.rig
.driver::<Position>()
.position
.x
.clamp(effective_min_x, effective_max_x);
} else {
let bounds_center_x = (cam.settings.bounds.min_x + cam.settings.bounds.max_x) * 0.5;
cam.rig.driver_mut::<Position>().position.x = bounds_center_x;
}
if effective_min_y <= effective_max_y {
cam.rig.driver_mut::<Position>().position.y = cam
.rig
.driver::<Position>()
.position
.y
.clamp(effective_min_y, effective_max_y);
} else {
let bounds_center_y = (cam.settings.bounds.min_y + cam.settings.bounds.max_y) * 0.5;
cam.rig.driver_mut::<Position>().position.y = bounds_center_y;
}
}
}
pub fn commit_camera_changes(
time: Res<Time>,
mut query_cam: Query<(&mut OgleCam, &mut Projection, &mut Transform)>,
) {
for (mut cam, mut projection, mut camera_transform) in query_cam.iter_mut() {
let Projection::Orthographic(ref mut projection) = projection.deref_mut() else {
continue;
};
cam.rig.update(time.delta_secs());
if cam.mode == OgleMode::Pancam {
let driver_pos = cam.rig.driver::<Position>().position;
cam.rig.final_transform.position.x = driver_pos.x;
cam.rig.final_transform.position.y = driver_pos.y;
}
camera_transform.translation = Vec3::new(
cam.rig.final_transform.position.x,
cam.rig.final_transform.position.y,
camera_transform.translation.z,
);
projection.scale = cam.rig.final_transform.position.z;
}
}