use glc::{ matrix::Matrix4f, misc::{BindGuard, Bindable}, shader::{Program, Type, Uniform}, texture::Texture, vector::Vector4f, }; use space_crush_common::{ components::{Player, PlayerOwned, Position, Ship, ShipType, Velocity}, misc::LogResult, }; use specs::{prelude::*, ReadExpect, ReadStorage, System, World}; use crate::{ constants::{PLAYER_COLOR_DEFAULT, UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, misc::WorldHelper, resources::Geometry, Error, }; pub struct Ships { program: Program, texture_bomber: Texture, texture_fighter: Texture, texture_transporter: Texture, location_model: gl::GLint, location_glow_color: gl::GLint, } impl Ships { pub fn new(world: &World) -> Result { let program = world.load_program(vec![ (Type::Vertex, "resources/shader/ship/vert.glsl"), (Type::Fragment, "resources/shader/ship/frag.glsl"), ])?; program.uniform_block_binding("Camera", UNIFORM_BUFFER_INDEX_CAMERA)?; program.uniform_block_binding("Global", UNIFORM_BUFFER_INDEX_UNIFORM)?; let location_model = program.uniform_location("uModel")?; let location_glow_color = program.uniform_location("uGlowColor")?; program.bind(); program.uniform("uTexture", Uniform::Texture(0))?; program.unbind(); let texture_bomber = world.load_texture("resources/textures/ship_bomber.png")?; let texture_fighter = world.load_texture("resources/textures/ship_fighter.png")?; let texture_transporter = world.load_texture("resources/textures/ship_transporter.png")?; Ok(Self { program, texture_bomber, texture_fighter, texture_transporter, location_model, location_glow_color, }) } } #[derive(SystemData)] pub struct ShipsData<'a> { geometry: ReadExpect<'a, Geometry>, position: ReadStorage<'a, Position>, velocity: ReadStorage<'a, Velocity>, ship: ReadStorage<'a, Ship>, owned: ReadStorage<'a, PlayerOwned>, player: ReadStorage<'a, Player>, } impl<'a> System<'a> for Ships { type SystemData = ShipsData<'a>; fn run(&mut self, data: Self::SystemData) { let ShipsData { geometry, position, velocity, ship, owned, player, } = data; gl::enable(gl::BLEND); gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); let _guard = BindGuard::new(&self.program); for (p, v, ship, owned) in (&position, &velocity, &ship, owned.maybe()).join() { let _guard = match ship.type_ { ShipType::Fighter => BindGuard::new(&self.texture_fighter), ShipType::Bomber => BindGuard::new(&self.texture_bomber), ShipType::Transporter => BindGuard::new(&self.texture_transporter), }; let c = match owned.and_then(|owned| player.get(owned.owner)) { Some(pv) => &pv.color, None => &*PLAYER_COLOR_DEFAULT, }; let p_x = p.pos.x; let p_y = p.pos.y; let d_x = v.dir.x; let d_y = v.dir.y; let s = p.size; let m = Matrix4f::new( Vector4f::new(-s * d_y, s * d_x, 0.0, 0.0), Vector4f::new(-s * d_x, -s * d_y, 0.0, 0.0), Vector4f::new(0.0, 0.0, s, 0.0), Vector4f::new(p_x, p_y, 0.0, 1.0), ); self.program .uniform(self.location_glow_color, Uniform::Vector4f(&c)) .error("Error while updating glow color"); self.program .uniform(self.location_model, Uniform::Matrix4f(&m)) .error("Error while updating model matrix"); geometry.render_quad(); } gl::disable(gl::BLEND); } }