chiron 0.1.0

Graphical and command-line interface tools for Biomechanics Foundation
Documentation
use bevy::prelude::*;
use bevy::render::camera::Viewport;
use bevy::window::PrimaryWindow;

mod pan_orbit;

use crate::ui;
use pan_orbit::pan_orbit_camera;
use pan_orbit::PanOrbitCamera;
use bevy_egui::EguiSettings;

pub struct CameraPlugin;

impl Plugin for CameraPlugin {
    fn build(&self, app: &mut App) {
        app.add_systems(Update, pan_orbit_camera)
            .add_systems(Startup, setup_camera)
            .add_systems(PostUpdate, set_camera_viewport.after(ui::show_ui_system))
            .init_resource::<CameraMode>();
    }
}

#[derive(Resource, Default, PartialEq)]
pub enum CameraMode {
    Fly,
    #[default]
    PanOrbit,
}

#[derive(Component)]
pub struct MainCamera;

pub fn setup_camera(mut commands: Commands) {
    commands.spawn((
        Camera3dBundle {
            transform: Transform::from_xyz(0., 4., 1.).looking_at(Vec3::new(0., 0., 1.), Vec3::Z),
            ..Default::default()
        },
        {
            PanOrbitCamera {
                ..Default::default()
            }
        },
        MainCamera,
    ));
}

pub fn set_camera_viewport(
    ui_state: Res<ui::UiState>,
    primary_window: Query<&mut Window, With<PrimaryWindow>>,
    egui_settings: Res<bevy_egui::EguiSettings>,
    mut cameras: Query<&mut Camera, With<MainCamera>>,
) {
    let mut cam = cameras.single_mut();

    let Ok(window) = primary_window.get_single() else {
        return;
    };

    let scale_factor = window.scale_factor() * egui_settings.scale_factor;

    let viewport_pos = ui_state.viewport_rect.left_top().to_vec2() * scale_factor as f32;
    let viewport_size = ui_state.viewport_rect.size() * scale_factor as f32;

    cam.viewport = Some(Viewport {
        physical_position: UVec2::new(viewport_pos.x as u32, viewport_pos.y as u32),
        physical_size: UVec2::new(viewport_size.x as u32, viewport_size.y as u32),
        depth: 0.0..1.0,
    });
}