use derive_new::new;
use winit::{DeviceEvent, Event, Window, WindowEvent};
#[cfg(feature = "profiler")]
use thread_profiler::profile_scope;
use amethyst_core::{
ecs::prelude::{
Join, Read, ReadExpect, ReadStorage, System, SystemData, World, Write, WriteStorage,
},
math::{convert, Unit, Vector3},
shrev::{EventChannel, ReaderId},
timing::Time,
transform::Transform,
SystemDesc,
};
use amethyst_derive::SystemDesc;
use amethyst_input::{get_input_axis_simple, BindingTypes, InputHandler};
use crate::{
components::{ArcBallControlTag, FlyControlTag},
resources::{HideCursor, WindowFocus},
};
#[derive(Debug, SystemDesc)]
#[system_desc(name(FlyMovementSystemDesc))]
pub struct FlyMovementSystem<T>
where
T: BindingTypes,
{
speed: f32,
right_input_axis: Option<T::Axis>,
up_input_axis: Option<T::Axis>,
forward_input_axis: Option<T::Axis>,
}
impl<T: BindingTypes> FlyMovementSystem<T> {
pub fn new(
speed: f32,
right_input_axis: Option<T::Axis>,
up_input_axis: Option<T::Axis>,
forward_input_axis: Option<T::Axis>,
) -> Self {
FlyMovementSystem {
speed,
right_input_axis,
up_input_axis,
forward_input_axis,
}
}
}
impl<'a, T: BindingTypes> System<'a> for FlyMovementSystem<T> {
type SystemData = (
Read<'a, Time>,
WriteStorage<'a, Transform>,
Read<'a, InputHandler<T>>,
ReadStorage<'a, FlyControlTag>,
);
fn run(&mut self, (time, mut transform, input, tag): Self::SystemData) {
#[cfg(feature = "profiler")]
profile_scope!("fly_movement_system");
let x = get_input_axis_simple(&self.right_input_axis, &input);
let y = get_input_axis_simple(&self.up_input_axis, &input);
let z = get_input_axis_simple(&self.forward_input_axis, &input);
if let Some(dir) = Unit::try_new(Vector3::new(x, y, z), convert(1.0e-6)) {
for (transform, _) in (&mut transform, &tag).join() {
let delta_sec = time.delta_seconds();
transform.append_translation_along(dir, delta_sec * self.speed);
}
}
}
}
#[derive(Debug, Default)]
pub struct ArcBallRotationSystem;
impl<'a> System<'a> for ArcBallRotationSystem {
type SystemData = (
WriteStorage<'a, Transform>,
ReadStorage<'a, ArcBallControlTag>,
);
fn run(&mut self, (mut transforms, tags): Self::SystemData) {
#[cfg(feature = "profiler")]
profile_scope!("arc_ball_rotation_system");
let mut position = None;
for (transform, arc_ball_camera_tag) in (&transforms, &tags).join() {
let pos_vec = transform.rotation() * -Vector3::z() * arc_ball_camera_tag.distance;
if let Some(target_transform) = transforms.get(arc_ball_camera_tag.target) {
position = Some(target_transform.translation() - pos_vec);
}
}
if let Some(new_pos) = position {
for (transform, _) in (&mut transforms, &tags).join() {
*transform.translation_mut() = new_pos;
}
}
}
}
#[derive(Debug, SystemDesc, new)]
#[system_desc(name(FreeRotationSystemDesc))]
pub struct FreeRotationSystem {
sensitivity_x: f32,
sensitivity_y: f32,
#[system_desc(event_channel_reader)]
event_reader: ReaderId<Event>,
}
impl<'a> System<'a> for FreeRotationSystem {
type SystemData = (
Read<'a, EventChannel<Event>>,
WriteStorage<'a, Transform>,
ReadStorage<'a, FlyControlTag>,
Read<'a, WindowFocus>,
Read<'a, HideCursor>,
);
fn run(&mut self, (events, mut transform, tag, focus, hide): Self::SystemData) {
#[cfg(feature = "profiler")]
profile_scope!("free_rotation_system");
let focused = focus.is_focused;
for event in events.read(&mut self.event_reader) {
if focused && hide.hide {
if let Event::DeviceEvent { ref event, .. } = *event {
if let DeviceEvent::MouseMotion { delta: (x, y) } = *event {
for (transform, _) in (&mut transform, &tag).join() {
transform.append_rotation_x_axis(
(-(y as f32) * self.sensitivity_y).to_radians(),
);
transform.prepend_rotation_y_axis(
(-(x as f32) * self.sensitivity_x).to_radians(),
);
}
}
}
}
}
}
}
#[derive(Debug, SystemDesc, new)]
#[system_desc(name(MouseFocusUpdateSystemDesc))]
pub struct MouseFocusUpdateSystem {
#[system_desc(event_channel_reader)]
event_reader: ReaderId<Event>,
}
impl<'a> System<'a> for MouseFocusUpdateSystem {
type SystemData = (Read<'a, EventChannel<Event>>, Write<'a, WindowFocus>);
fn run(&mut self, (events, mut focus): Self::SystemData) {
#[cfg(feature = "profiler")]
profile_scope!("mouse_focus_update_system");
for event in events.read(&mut self.event_reader) {
if let Event::WindowEvent { ref event, .. } = *event {
if let WindowEvent::Focused(focused) = *event {
focus.is_focused = focused;
}
}
}
}
}
#[derive(Debug, SystemDesc, new)]
#[system_desc(name(CursorHideSystemDesc))]
pub struct CursorHideSystem {
#[new(value = "true")]
#[system_desc(skip)]
is_hidden: bool,
}
impl Default for CursorHideSystem {
fn default() -> Self {
CursorHideSystem::new()
}
}
impl<'a> System<'a> for CursorHideSystem {
type SystemData = (
ReadExpect<'a, Window>,
Read<'a, HideCursor>,
Read<'a, WindowFocus>,
);
fn run(&mut self, (win, hide, focus): Self::SystemData) {
#[cfg(feature = "profiler")]
profile_scope!("cursor_hide_system");
let should_be_hidden = focus.is_focused && hide.hide;
if !self.is_hidden && should_be_hidden {
if let Err(err) = win.grab_cursor(true) {
log::error!("Unable to grab the cursor. Error: {:?}", err);
}
win.hide_cursor(true);
self.is_hidden = true;
} else if self.is_hidden && !should_be_hidden {
if let Err(err) = win.grab_cursor(false) {
log::error!("Unable to release the cursor. Error: {:?}", err);
}
win.hide_cursor(false);
self.is_hidden = false;
}
}
}