| @@ -284,7 +284,8 @@ where | |||||
| } | } | ||||
| #[inline] | #[inline] | ||||
| pub fn translate(v: Vector2<T>) -> Self { | |||||
| pub fn translate<V: Into<Vector2<T>>>(v: V) -> Self { | |||||
| let v = V::into(v); | |||||
| let one = T::one(); | let one = T::one(); | ||||
| let zro = T::zero(); | let zro = T::zero(); | ||||
| @@ -378,7 +379,8 @@ where | |||||
| T: Float, | T: Float, | ||||
| { | { | ||||
| #[inline] | #[inline] | ||||
| pub fn translate(v: Vector3<T>) -> Self { | |||||
| pub fn translate<V: Into<Vector3<T>>>(v: V) -> Self { | |||||
| let v = V::into(v); | |||||
| let one = T::one(); | let one = T::one(); | ||||
| let zero = T::zero(); | let zero = T::zero(); | ||||
| @@ -391,7 +393,8 @@ where | |||||
| } | } | ||||
| #[inline] | #[inline] | ||||
| pub fn scale(v: Vector3<T>) -> Self { | |||||
| pub fn scale<V: Into<Vector3<T>>>(v: V) -> Self { | |||||
| let v = V::into(v); | |||||
| let one = T::one(); | let one = T::one(); | ||||
| let zero = T::zero(); | let zero = T::zero(); | ||||
| @@ -405,8 +408,8 @@ where | |||||
| #[inline] | #[inline] | ||||
| #[allow(clippy::many_single_char_names)] | #[allow(clippy::many_single_char_names)] | ||||
| pub fn rotate(axis: Vector3<T>, angle: Angle<T>) -> Self { | |||||
| let axis = axis.normalize(); | |||||
| pub fn rotate<V: Into<Vector3<T>>>(axis: V, angle: Angle<T>) -> Self { | |||||
| let axis = V::into(axis).normalize(); | |||||
| let x = axis.x; | let x = axis.x; | ||||
| let y = axis.y; | let y = axis.y; | ||||
| let z = axis.z; | let z = axis.z; | ||||
| @@ -2,7 +2,7 @@ | |||||
| use std::convert::{AsMut, AsRef}; | use std::convert::{AsMut, AsRef}; | ||||
| use std::fmt::{Debug, Formatter, Result as FmtResult}; | use std::fmt::{Debug, Formatter, Result as FmtResult}; | ||||
| use std::ops::{Add, Deref, DerefMut, Mul, Sub}; | |||||
| use std::ops::{Add, Deref, DerefMut, Mul, Neg, Sub}; | |||||
| #[cfg(feature = "serde")] | #[cfg(feature = "serde")] | ||||
| use serde::{ | use serde::{ | ||||
| @@ -296,6 +296,21 @@ where | |||||
| } | } | ||||
| } | } | ||||
| impl<T> Neg for Vector2<T> | |||||
| where | |||||
| T: Numeric, | |||||
| { | |||||
| type Output = Self; | |||||
| #[inline] | |||||
| fn neg(self) -> Self::Output { | |||||
| Self { | |||||
| x: -self.x, | |||||
| y: -self.y, | |||||
| } | |||||
| } | |||||
| } | |||||
| impl<T> Add for Vector2<T> | impl<T> Add for Vector2<T> | ||||
| where | where | ||||
| T: Numeric, | T: Numeric, | ||||
| @@ -350,6 +365,15 @@ where | |||||
| } | } | ||||
| } | } | ||||
| impl<T> From<Vector3<T>> for Vector2<T> | |||||
| where | |||||
| T: Numeric, | |||||
| { | |||||
| fn from(vec3: Vector3<T>) -> Self { | |||||
| vec3.into_vec2() | |||||
| } | |||||
| } | |||||
| impl<T> From<Vector4<T>> for Vector2<T> | impl<T> From<Vector4<T>> for Vector2<T> | ||||
| where | where | ||||
| T: Numeric, | T: Numeric, | ||||
| @@ -408,6 +432,19 @@ where | |||||
| z: self.x * other.y - self.y * other.x, | z: self.x * other.y - self.y * other.x, | ||||
| } | } | ||||
| } | } | ||||
| #[inline] | |||||
| pub fn as_vec2(&self) -> &Vector2<T> { | |||||
| unsafe { &*(self as *const Vector3<T> as *const Vector2<T>) } | |||||
| } | |||||
| #[inline] | |||||
| pub fn into_vec2(self) -> Vector2<T> { | |||||
| Vector2 { | |||||
| x: self.x, | |||||
| y: self.y, | |||||
| } | |||||
| } | |||||
| } | } | ||||
| impl<T> Vector3<T> | impl<T> Vector3<T> | ||||
| @@ -424,6 +461,22 @@ where | |||||
| } | } | ||||
| } | } | ||||
| impl<T> Neg for Vector3<T> | |||||
| where | |||||
| T: Numeric, | |||||
| { | |||||
| type Output = Self; | |||||
| #[inline] | |||||
| fn neg(self) -> Self::Output { | |||||
| Self { | |||||
| x: -self.x, | |||||
| y: -self.y, | |||||
| z: -self.z, | |||||
| } | |||||
| } | |||||
| } | |||||
| impl<T> Add for Vector3<T> | impl<T> Add for Vector3<T> | ||||
| where | where | ||||
| T: Numeric, | T: Numeric, | ||||
| @@ -480,6 +533,28 @@ where | |||||
| } | } | ||||
| } | } | ||||
| impl<T> From<Vector2<T>> for Vector3<T> | |||||
| where | |||||
| T: Numeric, | |||||
| { | |||||
| fn from(vec2: Vector2<T>) -> Self { | |||||
| Self { | |||||
| x: vec2.x, | |||||
| y: vec2.y, | |||||
| z: T::zero(), | |||||
| } | |||||
| } | |||||
| } | |||||
| impl<T> From<Vector4<T>> for Vector3<T> | |||||
| where | |||||
| T: Numeric, | |||||
| { | |||||
| fn from(vec4: Vector4<T>) -> Self { | |||||
| vec4.into_vec3() | |||||
| } | |||||
| } | |||||
| /* Vector4 */ | /* Vector4 */ | ||||
| impl<T> Vector4<T> | impl<T> Vector4<T> | ||||
| @@ -1,5 +1,6 @@ | |||||
| use std::string::ToString; | use std::string::ToString; | ||||
| use glc::vector::Vector2f; | |||||
| use space_crush_common::{misc::LogResult, resources::Global}; | use space_crush_common::{misc::LogResult, resources::Global}; | ||||
| use specs::{prelude::*, Entities, ReadExpect, System}; | use specs::{prelude::*, Entities, ReadExpect, System}; | ||||
| @@ -15,8 +16,8 @@ pub struct Summary { | |||||
| cache: TextCache, | cache: TextCache, | ||||
| text: Text, | text: Text, | ||||
| fps: usize, | fps: usize, | ||||
| resolution: (u32, u32), | |||||
| mouse_pos: (f32, f32), | |||||
| resolution: Vector2f, | |||||
| mouse_pos: Vector2f, | |||||
| entity_count: usize, | entity_count: usize, | ||||
| } | } | ||||
| @@ -44,8 +45,8 @@ impl Summary { | |||||
| cache, | cache, | ||||
| text, | text, | ||||
| fps: 0, | fps: 0, | ||||
| resolution: (0, 0), | |||||
| mouse_pos: (0.0, 0.0), | |||||
| resolution: Default::default(), | |||||
| mouse_pos: Default::default(), | |||||
| entity_count: 0, | entity_count: 0, | ||||
| }) | }) | ||||
| } | } | ||||
| @@ -83,14 +84,14 @@ impl<'a> System<'a> for Summary { | |||||
| 4, | 4, | ||||
| &mut self.resolution, | &mut self.resolution, | ||||
| &input_state.resolution, | &input_state.resolution, | ||||
| |(w, h)| format!("{} | {}", w, h), | |||||
| |v| unsafe { format!("{:.0} | {:.0}", v.x, v.y) }, | |||||
| ); | ); | ||||
| update_text( | update_text( | ||||
| &mut self.text, | &mut self.text, | ||||
| 6, | 6, | ||||
| &mut self.mouse_pos, | &mut self.mouse_pos, | ||||
| &input_state.mouse_pos, | &input_state.mouse_pos, | ||||
| |(x, y)| format!("{:.2} | {:.2}", x, y), | |||||
| |v| unsafe { format!("{:.2} | {:.2}", v.x, v.y) }, | |||||
| ); | ); | ||||
| update_text( | update_text( | ||||
| &mut self.text, | &mut self.text, | ||||
| @@ -2,7 +2,7 @@ use glc::{ | |||||
| matrix::Matrix4f, | matrix::Matrix4f, | ||||
| misc::Bindable, | misc::Bindable, | ||||
| shader::{Program, Type}, | shader::{Program, Type}, | ||||
| vector::Vector3f, | |||||
| vector::{Vector2f, Vector3f}, | |||||
| }; | }; | ||||
| use shrev::{EventChannel, ReaderId}; | use shrev::{EventChannel, ReaderId}; | ||||
| use space_crush_common::{ | use space_crush_common::{ | ||||
| @@ -20,7 +20,7 @@ use crate::{ | |||||
| pub struct Init { | pub struct Init { | ||||
| program: Program, | program: Program, | ||||
| resolution: (u32, u32), | |||||
| resolution: Vector2f, | |||||
| mouse_event_id: ReaderId<MouseEvent>, | mouse_event_id: ReaderId<MouseEvent>, | ||||
| } | } | ||||
| @@ -30,7 +30,7 @@ impl Init { | |||||
| (Type::Vertex, "resources/shader/noise/vert.glsl"), | (Type::Vertex, "resources/shader/noise/vert.glsl"), | ||||
| (Type::Fragment, "resources/shader/noise/frag.glsl"), | (Type::Fragment, "resources/shader/noise/frag.glsl"), | ||||
| ])?; | ])?; | ||||
| let resolution = (0, 0); | |||||
| let resolution = Vector2f::default(); | |||||
| let mouse_event_id = world.register_event_reader::<MouseEvent>()?; | let mouse_event_id = world.register_event_reader::<MouseEvent>()?; | ||||
| world | world | ||||
| @@ -80,31 +80,30 @@ impl<'a> System<'a> for Init { | |||||
| if self.resolution != input_state.resolution { | if self.resolution != input_state.resolution { | ||||
| self.resolution = input_state.resolution; | self.resolution = input_state.resolution; | ||||
| gl::viewport(0, 0, self.resolution.0 as _, self.resolution.1 as _); | |||||
| gl::viewport(0, 0, self.resolution.x as _, self.resolution.y as _); | |||||
| camera | camera | ||||
| .resize(self.resolution.0 as _, self.resolution.1 as _) | |||||
| .resize(self.resolution.x, self.resolution.y) | |||||
| .error("Error while updating camera"); | .error("Error while updating camera"); | ||||
| } | } | ||||
| /* zoom */ | /* zoom */ | ||||
| let mouse_pos = &input_state.mouse_pos; | |||||
| let events = mouse_events.read(&mut self.mouse_event_id); | let events = mouse_events.read(&mut self.mouse_event_id); | ||||
| for event in events { | for event in events { | ||||
| match event { | match event { | ||||
| MouseEvent::ScrollY(delta) => { | MouseEvent::ScrollY(delta) => { | ||||
| let s = config.input.camera_zoom_speed; | let s = config.input.camera_zoom_speed; | ||||
| let z = s / (s - delta); | let z = s / (s - delta); | ||||
| let m = Matrix4f::translate((mouse_pos.0, mouse_pos.1, 0.0).into()) | |||||
| * Matrix4f::scale(z.into()) | |||||
| * Matrix4f::translate((-mouse_pos.0, -mouse_pos.1, 0.0).into()); | |||||
| let m = Matrix4f::translate(input_state.mouse_pos) | |||||
| * Matrix4f::scale(z) | |||||
| * Matrix4f::translate(-input_state.mouse_pos); | |||||
| camera | camera | ||||
| .update_with(move |v| m * v) | .update_with(move |v| m * v) | ||||
| .error("Error while zooming camera"); | .error("Error while zooming camera"); | ||||
| } | } | ||||
| MouseEvent::Delta(x, y) if input_state.button_state(&[MouseButton::Right]) => { | MouseEvent::Delta(x, y) if input_state.button_state(&[MouseButton::Right]) => { | ||||
| let m = Matrix4f::translate((*x, -*y, 0.0).into()); | |||||
| let m = Matrix4f::translate((*x, -*y, 0.0)); | |||||
| camera | camera | ||||
| .update_with(move |v| m * v) | .update_with(move |v| m * v) | ||||
| @@ -14,6 +14,7 @@ use space_crush_common::{ | |||||
| constants::VECTOR_2F_POS_X, | constants::VECTOR_2F_POS_X, | ||||
| misc::{LogResult, WorldHelper as _}, | misc::{LogResult, WorldHelper as _}, | ||||
| resources::Global, | resources::Global, | ||||
| return_if_none, | |||||
| }; | }; | ||||
| use specs::{prelude::*, Entities, ReadExpect, ReadStorage, System, World}; | use specs::{prelude::*, Entities, ReadExpect, ReadStorage, System, World}; | ||||
| @@ -44,9 +45,9 @@ pub struct SelectFleet { | |||||
| mouse_event_id: ReaderId<MouseEvent>, | mouse_event_id: ReaderId<MouseEvent>, | ||||
| select_mode: SelectMode, | select_mode: SelectMode, | ||||
| camera_counter: usize, | camera_counter: usize, | ||||
| camera_view_invert: Matrix4f, | |||||
| need_value_update: bool, | need_value_update: bool, | ||||
| values_changed_once: bool, | values_changed_once: bool, | ||||
| is_new_selection: bool, | |||||
| mouse_pos: Vector2f, | mouse_pos: Vector2f, | ||||
| count: ShipCount, | count: ShipCount, | ||||
| @@ -69,7 +70,7 @@ enum SelectMode { | |||||
| } | } | ||||
| #[derive(SystemData)] | #[derive(SystemData)] | ||||
| pub struct SelectFleetData<'a> { | |||||
| pub struct FleetSelectData<'a> { | |||||
| player_state: WriteExpect<'a, PlayerState>, | player_state: WriteExpect<'a, PlayerState>, | ||||
| camera: ReadExpect<'a, Camera>, | camera: ReadExpect<'a, Camera>, | ||||
| @@ -85,33 +86,24 @@ pub struct SelectFleetData<'a> { | |||||
| fleets: ReadStorage<'a, Fleet>, | fleets: ReadStorage<'a, Fleet>, | ||||
| } | } | ||||
| macro_rules! unwrap { | |||||
| ($value:expr) => { | |||||
| match $value { | |||||
| Some(value) => value, | |||||
| None => return, | |||||
| } | |||||
| }; | |||||
| } | |||||
| macro_rules! selection { | macro_rules! selection { | ||||
| (&$data:expr) => { | (&$data:expr) => { | ||||
| unwrap!(&$data.player_state.selection) | |||||
| return_if_none!(&$data.player_state.selection) | |||||
| }; | }; | ||||
| (&mut $data:expr) => { | (&mut $data:expr) => { | ||||
| unwrap!(&mut $data.player_state.selection) | |||||
| return_if_none!(&mut $data.player_state.selection) | |||||
| }; | }; | ||||
| } | } | ||||
| macro_rules! fleet_info { | macro_rules! fleet_info { | ||||
| (&$data:expr, $id:expr) => { | (&$data:expr, $id:expr) => { | ||||
| unwrap!($data.fleet_infos.get($id)) | |||||
| return_if_none!($data.fleet_infos.get($id)) | |||||
| }; | }; | ||||
| } | } | ||||
| macro_rules! position { | macro_rules! position { | ||||
| (&$data:expr, $id:expr) => { | (&$data:expr, $id:expr) => { | ||||
| unwrap!($data.positions.get($id)) | |||||
| return_if_none!($data.positions.get($id)) | |||||
| }; | }; | ||||
| } | } | ||||
| @@ -157,9 +149,9 @@ impl SelectFleet { | |||||
| mouse_event_id, | mouse_event_id, | ||||
| select_mode, | select_mode, | ||||
| camera_counter: 0, | camera_counter: 0, | ||||
| camera_view_invert: Default::default(), | |||||
| need_value_update: true, | need_value_update: true, | ||||
| values_changed_once: false, | values_changed_once: false, | ||||
| is_new_selection: true, | |||||
| mouse_pos: Default::default(), | mouse_pos: Default::default(), | ||||
| count: Default::default(), | count: Default::default(), | ||||
| @@ -172,39 +164,46 @@ impl SelectFleet { | |||||
| }) | }) | ||||
| } | } | ||||
| fn update_camera(&mut self, d: &SelectFleetData<'_>) { | |||||
| fn update_camera(&mut self, d: &FleetSelectData<'_>) { | |||||
| let camera_counter = d.camera.update_counter(); | let camera_counter = d.camera.update_counter(); | ||||
| if self.camera_counter != camera_counter { | if self.camera_counter != camera_counter { | ||||
| self.camera_counter = camera_counter; | self.camera_counter = camera_counter; | ||||
| self.need_value_update = true; | self.need_value_update = true; | ||||
| self.camera_view_invert = d.camera.view().invert(); | |||||
| } | } | ||||
| } | } | ||||
| fn handle_events(&mut self, d: &mut SelectFleetData<'_>) { | |||||
| fn handle_events(&mut self, d: &mut FleetSelectData<'_>) { | |||||
| let events = d.mouse_events.read(&mut self.mouse_event_id); | let events = d.mouse_events.read(&mut self.mouse_event_id); | ||||
| for event in events { | for event in events { | ||||
| match event { | match event { | ||||
| MouseEvent::ButtonDown(button) if button == &d.config.input.fleet_select_button => { | MouseEvent::ButtonDown(button) if button == &d.config.input.fleet_select_button => { | ||||
| let pos = self.window_to_world(d.input_state.mouse_pos); | |||||
| let pos = d.camera.view_to_world(d.input_state.mouse_pos); | |||||
| let selection = d.player_state.selection.take(); | let selection = d.player_state.selection.take(); | ||||
| for (id, position, fleet) in (&d.entities, &d.positions, &d.fleets).join() { | for (id, position, fleet) in (&d.entities, &d.positions, &d.fleets).join() { | ||||
| let r = fleet.orbit_max * fleet.orbit_max; | let r = fleet.orbit_max * fleet.orbit_max; | ||||
| if (position.pos - pos).length_sqr() <= r { | if (position.pos - pos).length_sqr() <= r { | ||||
| d.player_state.selection = match selection { | d.player_state.selection = match selection { | ||||
| Some(s) if s.fleet == id => Some(s), | |||||
| _ => Some(Selection { | |||||
| fleet: id, | |||||
| count: ShipCount::all(), | |||||
| }), | |||||
| Some(s) if s.fleet == id => { | |||||
| self.is_new_selection = false; | |||||
| Some(s) | |||||
| } | |||||
| _ => { | |||||
| self.is_new_selection = true; | |||||
| Some(Selection { | |||||
| fleet: id, | |||||
| count: ShipCount::none(), | |||||
| }) | |||||
| } | |||||
| }; | }; | ||||
| let selection = selection!(&d); | let selection = selection!(&d); | ||||
| let fleet_info = fleet_info!(&d, selection.fleet); | let fleet_info = fleet_info!(&d, selection.fleet); | ||||
| let timeout = Instant::now() + FLEET_SELECT_DETAIL_TIMEOUT; | let timeout = Instant::now() + FLEET_SELECT_DETAIL_TIMEOUT; | ||||
| self.mouse_pos = d.input_state.mouse_pos.into(); | |||||
| self.mouse_pos = d.input_state.mouse_pos; | |||||
| self.select_mode = SelectMode::Init(timeout); | self.select_mode = SelectMode::Init(timeout); | ||||
| self.values_changed_once = false; | self.values_changed_once = false; | ||||
| self.set_count(selection.count, &fleet_info.count); | self.set_count(selection.count, &fleet_info.count); | ||||
| @@ -218,36 +217,41 @@ impl SelectFleet { | |||||
| SelectMode::Simple(progress) => { | SelectMode::Simple(progress) => { | ||||
| selection!(&mut d).count = self.count; | selection!(&mut d).count = self.count; | ||||
| self.mouse_pos = d.input_state.mouse_pos.into(); | |||||
| self.mouse_pos = d.input_state.mouse_pos; | |||||
| SelectMode::SimpleClose(progress) | SelectMode::SimpleClose(progress) | ||||
| } | } | ||||
| SelectMode::Detail(progress) => { | SelectMode::Detail(progress) => { | ||||
| selection!(&mut d).count = self.count; | selection!(&mut d).count = self.count; | ||||
| self.mouse_pos = d.input_state.mouse_pos.into(); | |||||
| self.mouse_pos = d.input_state.mouse_pos; | |||||
| SelectMode::DetailClose(progress) | SelectMode::DetailClose(progress) | ||||
| } | } | ||||
| SelectMode::Init(_) if self.is_new_selection => { | |||||
| selection!(&mut d).count = ShipCount::all(); | |||||
| SelectMode::None | |||||
| } | |||||
| _ => SelectMode::None, | _ => SelectMode::None, | ||||
| } | } | ||||
| } | } | ||||
| MouseEvent::Move(_, _) if self.select_mode.is_init() => { | MouseEvent::Move(_, _) if self.select_mode.is_init() => { | ||||
| self.need_value_update = true; | self.need_value_update = true; | ||||
| self.values_changed_once = false; | self.values_changed_once = false; | ||||
| self.mouse_pos = d.input_state.mouse_pos.into(); | |||||
| self.mouse_pos = d.input_state.mouse_pos; | |||||
| self.select_mode = SelectMode::Simple(0.0); | self.select_mode = SelectMode::Simple(0.0); | ||||
| } | } | ||||
| MouseEvent::Move(_, _) if self.select_mode.is_active() => { | MouseEvent::Move(_, _) if self.select_mode.is_active() => { | ||||
| self.need_value_update = true; | self.need_value_update = true; | ||||
| self.mouse_pos = d.input_state.mouse_pos.into(); | |||||
| self.mouse_pos = d.input_state.mouse_pos; | |||||
| } | } | ||||
| _ => (), | _ => (), | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| fn update(&mut self, d: &SelectFleetData<'_>) { | |||||
| fn update(&mut self, d: &FleetSelectData<'_>) { | |||||
| if !self.select_mode.is_active() { | if !self.select_mode.is_active() { | ||||
| return; | return; | ||||
| } | } | ||||
| @@ -261,7 +265,7 @@ impl SelectFleet { | |||||
| let position = position!(&d, selection.fleet); | let position = position!(&d, selection.fleet); | ||||
| let fleet_info = fleet_info!(&d, selection.fleet); | let fleet_info = fleet_info!(&d, selection.fleet); | ||||
| self.marker = self.window_to_world(self.mouse_pos) - position.pos; | |||||
| self.marker = d.camera.view_to_world(self.mouse_pos) - position.pos; | |||||
| self.zoom = d.camera.view().axis_x.as_vec3().length(); | self.zoom = d.camera.view().axis_x.as_vec3().length(); | ||||
| self.shape_size = position.shape.radius().unwrap_or(0.0); | self.shape_size = position.shape.radius().unwrap_or(0.0); | ||||
| self.ring0 = self.shape_size + FLEET_SELECT_OFFSET / self.zoom; | self.ring0 = self.shape_size + FLEET_SELECT_OFFSET / self.zoom; | ||||
| @@ -400,7 +404,7 @@ impl SelectFleet { | |||||
| } | } | ||||
| } | } | ||||
| fn render(&mut self, progress: f32, d: &SelectFleetData<'_>) { | |||||
| fn render(&mut self, progress: f32, d: &FleetSelectData<'_>) { | |||||
| /* select program */ | /* select program */ | ||||
| let is_simple = self.select_mode.is_simple(); | let is_simple = self.select_mode.is_simple(); | ||||
| let program = if is_simple { | let program = if is_simple { | ||||
| @@ -500,15 +504,11 @@ impl SelectFleet { | |||||
| self.values[3] = sum / total_max; | self.values[3] = sum / total_max; | ||||
| } | } | ||||
| fn window_to_world<T: Into<Vector2f>>(&self, pos: T) -> Vector2f { | |||||
| (self.camera_view_invert * T::into(pos).into_vec4()).into_vec2() | |||||
| } | |||||
| fn text_pos<T: Into<Vector2f>>( | fn text_pos<T: Into<Vector2f>>( | ||||
| &self, | &self, | ||||
| dir: T, | dir: T, | ||||
| fleet_pos: Vector2f, | fleet_pos: Vector2f, | ||||
| d: &SelectFleetData<'_>, | |||||
| d: &FleetSelectData<'_>, | |||||
| ) -> Vector2f { | ) -> Vector2f { | ||||
| let text_offset = self.ring1 + FLEET_SELECT_TEXT_OFFSET / self.zoom.sqrt(); | let text_offset = self.ring1 + FLEET_SELECT_TEXT_OFFSET / self.zoom.sqrt(); | ||||
| let pos = fleet_pos + T::into(dir).normalize() * text_offset; | let pos = fleet_pos + T::into(dir).normalize() * text_offset; | ||||
| @@ -518,7 +518,7 @@ impl SelectFleet { | |||||
| } | } | ||||
| impl<'a> System<'a> for SelectFleet { | impl<'a> System<'a> for SelectFleet { | ||||
| type SystemData = SelectFleetData<'a>; | |||||
| type SystemData = FleetSelectData<'a>; | |||||
| fn run(&mut self, mut data: Self::SystemData) { | fn run(&mut self, mut data: Self::SystemData) { | ||||
| self.update_camera(&data); | self.update_camera(&data); | ||||
| @@ -10,6 +10,8 @@ use glc::{ | |||||
| pub struct Camera { | pub struct Camera { | ||||
| buffer: ArrayBuffer, | buffer: ArrayBuffer, | ||||
| data: Data, | data: Data, | ||||
| view_invert: Matrix4f, | |||||
| projection_invert: Matrix4f, | |||||
| update_counter: usize, | update_counter: usize, | ||||
| } | } | ||||
| @@ -34,6 +36,8 @@ impl Camera { | |||||
| Ok(Self { | Ok(Self { | ||||
| buffer, | buffer, | ||||
| data, | data, | ||||
| view_invert: Default::default(), | |||||
| projection_invert: Default::default(), | |||||
| update_counter: 0, | update_counter: 0, | ||||
| }) | }) | ||||
| } | } | ||||
| @@ -42,10 +46,18 @@ impl Camera { | |||||
| &self.data.projection | &self.data.projection | ||||
| } | } | ||||
| pub fn projection_invert(&self) -> &Matrix4f { | |||||
| &self.projection_invert | |||||
| } | |||||
| pub fn view(&self) -> &Matrix4f { | pub fn view(&self) -> &Matrix4f { | ||||
| &self.data.view | &self.data.view | ||||
| } | } | ||||
| pub fn view_invert(&self) -> &Matrix4f { | |||||
| &self.view_invert | |||||
| } | |||||
| pub fn update_counter(&self) -> usize { | pub fn update_counter(&self) -> usize { | ||||
| self.update_counter | self.update_counter | ||||
| } | } | ||||
| @@ -63,6 +75,7 @@ impl Camera { | |||||
| data[0].size = self.data.size; | data[0].size = self.data.size; | ||||
| self.update_counter = self.update_counter.wrapping_add(1); | self.update_counter = self.update_counter.wrapping_add(1); | ||||
| self.projection_invert = self.data.projection.invert(); | |||||
| Ok(()) | Ok(()) | ||||
| } | } | ||||
| @@ -81,6 +94,7 @@ impl Camera { | |||||
| data[0].view = self.data.view; | data[0].view = self.data.view; | ||||
| self.update_counter = self.update_counter.wrapping_add(1); | self.update_counter = self.update_counter.wrapping_add(1); | ||||
| self.view_invert = self.data.view.invert(); | |||||
| Ok(()) | Ok(()) | ||||
| } | } | ||||
| @@ -89,11 +103,43 @@ impl Camera { | |||||
| Error::checked(|| self.buffer.bind_buffer_base(index)) | Error::checked(|| self.buffer.bind_buffer_base(index)) | ||||
| } | } | ||||
| pub fn world_to_view<T: Into<Vector2f>>(&self, pos: T) -> Vector2f { | |||||
| self.data.view.transform(T::into(pos)).into() | |||||
| } | |||||
| pub fn view_to_world<T: Into<Vector2f>>(&self, pos: T) -> Vector2f { | |||||
| self.view_invert.transform(T::into(pos)).into() | |||||
| } | |||||
| pub fn view_to_window<T: Into<Vector2f>>(&self, pos: T) -> Vector2f { | |||||
| view_to_window(&self.data.size, pos) | |||||
| } | |||||
| pub fn window_to_view<T: Into<Vector2f>>(&self, pos: T) -> Vector2f { | |||||
| window_to_view(&self.data.size, pos) | |||||
| } | |||||
| pub fn world_to_window<T: Into<Vector2f>>(&self, pos: T) -> Vector2f { | pub fn world_to_window<T: Into<Vector2f>>(&self, pos: T) -> Vector2f { | ||||
| let mut pos = self.data.view.transform(T::into(pos)).into_vec2(); | |||||
| pos.x += self.data.size.x / 2.0; | |||||
| pos.y = self.data.size.y / 2.0 - pos.y; | |||||
| self.view_to_window(self.world_to_view(pos)) | |||||
| } | |||||
| pos | |||||
| pub fn window_to_world<T: Into<Vector2f>>(&self, pos: T) -> Vector2f { | |||||
| self.view_to_world(self.window_to_view(pos)) | |||||
| } | } | ||||
| } | } | ||||
| pub fn view_to_window<T: Into<Vector2f>>(res: &Vector2f, pos: T) -> Vector2f { | |||||
| let mut pos = T::into(pos); | |||||
| pos.x += res.x / 2.0; | |||||
| pos.y = res.y / 2.0 - pos.y; | |||||
| pos | |||||
| } | |||||
| pub fn window_to_view<T: Into<Vector2f>>(res: &Vector2f, pos: T) -> Vector2f { | |||||
| let mut pos = T::into(pos); | |||||
| pos.x -= res.x / 2.0; | |||||
| pos.y = res.y / 2.0 - pos.y; | |||||
| pos | |||||
| } | |||||
| @@ -3,12 +3,14 @@ | |||||
| use std::collections::HashSet; | use std::collections::HashSet; | ||||
| use std::iter::IntoIterator; | use std::iter::IntoIterator; | ||||
| use glc::vector::Vector2f; | |||||
| use crate::misc::{MouseButton, VirtualKeyCode}; | use crate::misc::{MouseButton, VirtualKeyCode}; | ||||
| #[derive(Default)] | #[derive(Default)] | ||||
| pub struct InputState { | pub struct InputState { | ||||
| pub mouse_pos: (f32, f32), | |||||
| pub resolution: (u32, u32), | |||||
| pub mouse_pos: Vector2f, | |||||
| pub resolution: Vector2f, | |||||
| pub close_requested: bool, | pub close_requested: bool, | ||||
| pub key_states: HashSet<VirtualKeyCode>, | pub key_states: HashSet<VirtualKeyCode>, | ||||
| pub button_states: HashSet<MouseButton>, | pub button_states: HashSet<MouseButton>, | ||||
| @@ -1,9 +1,9 @@ | |||||
| mod camera; | |||||
| mod config; | |||||
| mod geometry; | |||||
| mod input_state; | |||||
| mod player_state; | |||||
| mod uniform; | |||||
| pub mod camera; | |||||
| pub mod config; | |||||
| pub mod geometry; | |||||
| pub mod input_state; | |||||
| pub mod player_state; | |||||
| pub mod uniform; | |||||
| pub use camera::Camera; | pub use camera::Camera; | ||||
| pub use config::Config; | pub use config::Config; | ||||
| @@ -4,7 +4,7 @@ use specs::{prelude::*, ReadExpect, System, World, Write}; | |||||
| use crate::{ | use crate::{ | ||||
| misc::{KeyboardEvent, MouseEvent, WindowEvent}, | misc::{KeyboardEvent, MouseEvent, WindowEvent}, | ||||
| resources::InputState, | |||||
| resources::{camera::window_to_view, InputState}, | |||||
| Error, | Error, | ||||
| }; | }; | ||||
| @@ -51,10 +51,7 @@ impl<'a> System<'a> for StateUpdate { | |||||
| for event in events { | for event in events { | ||||
| match event { | match event { | ||||
| MouseEvent::Move(x, y) => { | MouseEvent::Move(x, y) => { | ||||
| let x = *x - input_state.resolution.0 as f32 / 2.0; | |||||
| let y = input_state.resolution.1 as f32 / 2.0 - *y; | |||||
| input_state.mouse_pos = (x, y); | |||||
| input_state.mouse_pos = window_to_view(&input_state.resolution, (*x, *y)) | |||||
| } | } | ||||
| MouseEvent::ButtonUp(button) => input_state.set_button_state(*button, false), | MouseEvent::ButtonUp(button) => input_state.set_button_state(*button, false), | ||||
| MouseEvent::ButtonDown(button) => input_state.set_button_state(*button, true), | MouseEvent::ButtonDown(button) => input_state.set_button_state(*button, true), | ||||
| @@ -66,7 +63,7 @@ impl<'a> System<'a> for StateUpdate { | |||||
| for event in events { | for event in events { | ||||
| match event { | match event { | ||||
| WindowEvent::Resize(w, h) => { | WindowEvent::Resize(w, h) => { | ||||
| input_state.resolution = (*w, *h); | |||||
| input_state.resolution = (*w as f32, *h as f32).into(); | |||||
| } | } | ||||
| WindowEvent::Close => { | WindowEvent::Close => { | ||||
| input_state.close_requested = true; | input_state.close_requested = true; | ||||
| @@ -40,6 +40,14 @@ impl Count { | |||||
| } | } | ||||
| } | } | ||||
| pub fn none() -> Self { | |||||
| Self { | |||||
| fighter: 0, | |||||
| bomber: 0, | |||||
| transporter: 0, | |||||
| } | |||||
| } | |||||
| pub fn total(&self) -> usize { | pub fn total(&self) -> usize { | ||||
| self.fighter | self.fighter | ||||
| .saturating_add(self.bomber) | .saturating_add(self.bomber) | ||||
| @@ -2,6 +2,7 @@ pub mod components; | |||||
| pub mod constants; | pub mod constants; | ||||
| pub mod dispatcher; | pub mod dispatcher; | ||||
| pub mod error; | pub mod error; | ||||
| pub mod macros; | |||||
| pub mod misc; | pub mod misc; | ||||
| pub mod resources; | pub mod resources; | ||||
| pub mod systems; | pub mod systems; | ||||
| @@ -0,0 +1,19 @@ | |||||
| #[macro_export] | |||||
| macro_rules! return_if_none { | |||||
| ($value:expr) => { | |||||
| match $value { | |||||
| Some(value) => value, | |||||
| None => return, | |||||
| } | |||||
| }; | |||||
| } | |||||
| #[macro_export] | |||||
| macro_rules! break_if_none { | |||||
| ($value:expr) => { | |||||
| match $value { | |||||
| Some(value) => value, | |||||
| None => break, | |||||
| } | |||||
| }; | |||||
| } | |||||