use glc::{ matrix::Matrix4f, misc::{BindGuard, Bindable}, shader::{Program, Type, Uniform}, texture::Texture, vector::Vector4f, }; use space_crush_common::{ components::{Asteroid, AsteroidType, Player, PlayerOwned, Position}, 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 Asteroids { program: Program, texture_metal: Texture, texture_crystal: Texture, location_model: gl::GLint, location_glow_color: gl::GLint, } impl Asteroids { pub fn new(world: &World) -> Result { let program = world.load_program(vec![ (Type::Vertex, "resources/shader/asteroid/vert.glsl"), (Type::Fragment, "resources/shader/asteroid/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_metal = world.load_texture("resources/textures/asteroid_metal.png")?; let texture_crystal = world.load_texture("resources/textures/asteroid_crystal.png")?; Ok(Self { program, texture_metal, texture_crystal, location_model, location_glow_color, }) } } #[derive(SystemData)] pub struct AsteroidsData<'a> { geometry: ReadExpect<'a, Geometry>, position: ReadStorage<'a, Position>, asteroid: ReadStorage<'a, Asteroid>, owned: ReadStorage<'a, PlayerOwned>, player: ReadStorage<'a, Player>, } impl<'a> System<'a> for Asteroids { type SystemData = AsteroidsData<'a>; fn run(&mut self, data: Self::SystemData) { let AsteroidsData { geometry, position, asteroid, 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 (position, asteroid, owned) in (&position, &asteroid, owned.maybe()).join() { let p_x = position.pos.x; let p_y = position.pos.y; let s = position.size; let _guard = match asteroid.type_ { AsteroidType::Metal => BindGuard::new(&self.texture_metal), AsteroidType::Crystal => BindGuard::new(&self.texture_crystal), }; let c = match owned.and_then(|owned| player.get(owned.owner)) { Some(pv) => &pv.color, None => &*PLAYER_COLOR_DEFAULT, }; let m = Matrix4f::new( Vector4f::new(s, 0.0, 0.0, 0.0), Vector4f::new(0.0, s, 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); } }