@@ -306,9 +306,9 @@ where | |||
} | |||
#[inline] | |||
pub fn multiply(&self, other: &Self) -> Self { | |||
pub fn multiply<M: Borrow<Self>>(&self, other: M) -> Self { | |||
let m1 = self; | |||
let m2 = other; | |||
let m2 = other.borrow(); | |||
macro_rules! mul { | |||
($x:tt, $y:tt) => { | |||
@@ -440,9 +440,9 @@ where | |||
} | |||
#[inline] | |||
pub fn multiply(&self, other: &Self) -> Self { | |||
pub fn multiply<M: Borrow<Self>>(&self, other: M) -> Self { | |||
let m1 = self; | |||
let m2 = other; | |||
let m2 = other.borrow(); | |||
macro_rules! mul { | |||
($x:tt, $y:tt) => { | |||
@@ -462,8 +462,9 @@ where | |||
} | |||
#[inline] | |||
pub fn transform(&self, v: &Vector4<T>) -> Vector4<T> { | |||
pub fn transform<V: Into<Vector4<T>>>(&self, v: V) -> Vector4<T> { | |||
let m = self; | |||
let v = V::into(v); | |||
macro_rules! mul { | |||
($i:tt) => { | |||
@@ -629,7 +630,7 @@ macro_rules! impl_mul_mat4 { | |||
type Output = $output; | |||
fn mul(self, rhs: $input) -> Self::Output { | |||
self.$func(&rhs) | |||
self.$func(rhs) | |||
} | |||
} | |||
@@ -640,7 +641,7 @@ macro_rules! impl_mul_mat4 { | |||
type Output = $output; | |||
fn mul(self, rhs: $input) -> Self::Output { | |||
self.$func(&rhs) | |||
self.$func(rhs) | |||
} | |||
} | |||
}; | |||
@@ -649,7 +650,6 @@ macro_rules! impl_mul_mat4 { | |||
impl_mul_mat4!(Matrix4<T>, Matrix4<T>, multiply); | |||
impl_mul_mat4!(&Matrix4<T>, Matrix4<T>, multiply); | |||
impl_mul_mat4!(Vector4<T>, Vector4<T>, transform); | |||
impl_mul_mat4!(&Vector4<T>, Vector4<T>, transform); | |||
#[cfg(test)] | |||
mod tests { | |||
@@ -2,19 +2,45 @@ use glc::vector::{Angle, Vector2f, Vector4f}; | |||
use space_crush_common::{ | |||
components::{Fleet, Position}, | |||
constants::SHIP_ORBIT_DISTANCE_MAX, | |||
misc::LogResult, | |||
}; | |||
use specs::{prelude::*, ReadStorage, System, World, WriteExpect}; | |||
use crate::resources::Geometry; | |||
use crate::{ | |||
components::FleetInfo, | |||
misc::{HorizontalAlign, Text, TextManager, VerticalAlign}, | |||
resources::{Camera, Geometry}, | |||
Error, | |||
}; | |||
#[derive(Default)] | |||
pub struct Fleets; | |||
pub struct Fleets { | |||
text: Text, | |||
} | |||
#[derive(SystemData)] | |||
pub struct FleetData<'a> { | |||
geometry: WriteExpect<'a, Geometry>, | |||
position: ReadStorage<'a, Position>, | |||
fleet: ReadStorage<'a, Fleet>, | |||
camera: ReadExpect<'a, Camera>, | |||
positions: ReadStorage<'a, Position>, | |||
fleets: ReadStorage<'a, Fleet>, | |||
fleet_infos: ReadStorage<'a, FleetInfo>, | |||
} | |||
impl Fleets { | |||
pub fn new(manager: &TextManager) -> Result<Self, Error> { | |||
let cache = manager.create_cache()?; | |||
let text = cache | |||
.new_text() | |||
.scale(20.0) | |||
.font("resources/fonts/DroidSansMono.ttf") | |||
.color(0.7, 0.7, 0.7, 1.0) | |||
.vert_align(VerticalAlign::Center) | |||
.horz_align(HorizontalAlign::Center) | |||
.text("") | |||
.build()?; | |||
Ok(Self { text }) | |||
} | |||
} | |||
impl<'a> System<'a> for Fleets { | |||
@@ -23,28 +49,47 @@ impl<'a> System<'a> for Fleets { | |||
fn run(&mut self, data: Self::SystemData) { | |||
let FleetData { | |||
mut geometry, | |||
position, | |||
fleet, | |||
camera, | |||
positions, | |||
fleets, | |||
fleet_infos, | |||
} = data; | |||
gl::enable(gl::BLEND); | |||
gl::blend_func(gl::SRC_ALPHA, gl::ONE); | |||
for (p, f) in (&position, &fleet).join() { | |||
for (position, fleet, fleet_info) in (&positions, &fleets, &fleet_infos).join() { | |||
gl::blend_func(gl::SRC_ALPHA, gl::ONE); | |||
gl::blend_equation(gl::FUNC_ADD); | |||
geometry.render_lines( | |||
Vector4f::new(0.5, 0.5, 0.5, 0.05), | |||
&create_circle(p.pos, f.orbit_min), | |||
&create_circle(position.pos, fleet.orbit_min), | |||
); | |||
geometry.render_lines( | |||
Vector4f::new(0.5, 0.5, 0.5, 0.05), | |||
&create_circle(p.pos, f.orbit_max), | |||
&create_circle(position.pos, fleet.orbit_max), | |||
); | |||
geometry.render_lines( | |||
Vector4f::new(0.5, 0.5, 0.5, 0.05), | |||
&create_circle(p.pos, SHIP_ORBIT_DISTANCE_MAX * f.orbit_max), | |||
&create_circle(position.pos, SHIP_ORBIT_DISTANCE_MAX * fleet.orbit_max), | |||
); | |||
gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); | |||
gl::blend_equation(gl::FUNC_SUBTRACT); | |||
self.text | |||
.update( | |||
0, | |||
format!( | |||
"F:{}\nB:{}\nT:{}", | |||
fleet_info.count.fighter, | |||
fleet_info.count.bomber, | |||
fleet_info.count.transporter | |||
), | |||
) | |||
.panic("Unable to update text") | |||
.render_offset(&camera.world_to_window(position.pos)); | |||
} | |||
gl::blend_equation(gl::FUNC_ADD); | |||
gl::disable(gl::BLEND); | |||
} | |||
} | |||
@@ -53,8 +53,8 @@ impl<'a, 'b> App<'a, 'b> { | |||
.with_thread_local(Asteroids::new(world)?) | |||
.with_thread_local(Ships::new(world)?) | |||
.with_thread_local(SelectFleet::new(world, &text_manager)?) | |||
// .with_thread_local(DebugShips::default()) | |||
// .with_thread_local(DebugFleets::default()) | |||
.with_thread_local(DebugShips::default()) | |||
.with_thread_local(DebugFleets::new(&text_manager)?) | |||
.with_thread_local(DebugSummary::new(&text_manager)?) | |||
.build(); | |||
dispatcher.setup(world); | |||
@@ -83,7 +83,7 @@ fn create_world(world: &mut World, player_id: Entity) { | |||
.create_entity() | |||
.marked::<<PersistWorld as Persistence>::Marker>() | |||
.with(Position { | |||
pos: Vector2f::new(500.0, -500.0), | |||
pos: Vector2f::new(1000.0, -1000.0), | |||
shape: Shape::Circle(100.0), | |||
}) | |||
.with(Fleet { | |||
@@ -100,7 +100,7 @@ fn create_world(world: &mut World, player_id: Entity) { | |||
.create_entity() | |||
.marked::<<PersistWorld as Persistence>::Marker>() | |||
.with(Position { | |||
pos: Vector2f::new(500.0, 500.0), | |||
pos: Vector2f::new(1000.0, 1000.0), | |||
shape: Shape::Circle(100.0), | |||
}) | |||
.with(Fleet { | |||
@@ -129,7 +129,22 @@ fn create_world(world: &mut World, player_id: Entity) { | |||
.with(Planet {}) | |||
.build(); | |||
for i in 0..10 { | |||
world | |||
.create_entity() | |||
.marked::<<PersistWorld as Persistence>::Marker>() | |||
.with(Position { | |||
pos: Vector2f::new(2000.0, 0.0), | |||
shape: Shape::Circle(250.0), | |||
}) | |||
.with(Fleet { | |||
orbit_min: 325.0, | |||
orbit_max: 425.0, | |||
}) | |||
.with(FleetInfo::default()) | |||
.with(Planet {}) | |||
.build(); | |||
for i in 0..30 { | |||
world | |||
.create_entity() | |||
.marked::<<PersistWorld as Persistence>::Marker>() | |||
@@ -513,11 +513,7 @@ impl SelectFleet { | |||
let text_offset = self.ring1 + FLEET_SELECT_TEXT_OFFSET / self.zoom.sqrt(); | |||
let pos = fleet_pos + T::into(dir).normalize() * text_offset; | |||
let mut pos = (d.camera.view() * pos.into_vec4()).into_vec2(); | |||
pos.x += d.input_state.resolution.0 as f32 / 2.0; | |||
pos.y = d.input_state.resolution.1 as f32 / 2.0 - pos.y; | |||
pos | |||
d.camera.world_to_window(pos) | |||
} | |||
} | |||
@@ -88,4 +88,12 @@ impl Camera { | |||
pub fn bind(&self, index: gl::GLuint) -> Result<(), Error> { | |||
Error::checked(|| self.buffer.bind_buffer_base(index)) | |||
} | |||
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; | |||
pos | |||
} | |||
} |