use glc::{ matrix::Matrix4f, misc::Bindable, shader::{Program, Type}, vector::{Vector2f, Vector3f}, }; use shrev::{EventChannel, ReaderId}; use space_crush_common::{ misc::{LogResult, WorldHelper as _}, resources::Global, }; use specs::{prelude::*, ReadExpect, System, World, WriteExpect}; use crate::{ constants::{UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, misc::{ControlEvent, MouseButton, MouseEvent, WorldHelper}, resources::{Camera, Config, Geometry, InputState, Uniform}, Error, }; pub struct Init { program: Program, resolution: Vector2f, mouse_event_id: ReaderId, } impl Init { pub fn new(world: &mut World) -> Result { let program = world.load_program(vec![ (Type::Vertex, "resources/shader/noise/vert.glsl"), (Type::Fragment, "resources/shader/noise/frag.glsl"), ])?; let resolution = Vector2f::default(); let mouse_event_id = world.register_event_reader::()?; world .resource::()? .bind(UNIFORM_BUFFER_INDEX_CAMERA)?; world .resource::()? .bind(UNIFORM_BUFFER_INDEX_UNIFORM)?; Ok(Self { program, resolution, mouse_event_id, }) } } #[derive(SystemData)] pub struct InitData<'a> { camera: WriteExpect<'a, Camera>, uniform: WriteExpect<'a, Uniform>, control_events: WriteExpect<'a, EventChannel>, global: ReadExpect<'a, Global>, config: ReadExpect<'a, Config>, geometry: ReadExpect<'a, Geometry>, input_state: ReadExpect<'a, InputState>, mouse_events: ReadExpect<'a, EventChannel>, } impl<'a> System<'a> for Init { type SystemData = InitData<'a>; fn run(&mut self, data: Self::SystemData) { let InitData { mut camera, mut uniform, mut control_events, global, config, geometry, input_state, mouse_events, } = data; /* screen size */ if self.resolution != input_state.resolution { self.resolution = input_state.resolution; gl::viewport(0, 0, self.resolution.x as _, self.resolution.y as _); camera .resize(self.resolution.x, self.resolution.y) .error("Error while updating camera"); } /* zoom */ let events = mouse_events.read(&mut self.mouse_event_id); for event in events { match event { MouseEvent::ScrollY(delta) => { let s = config.input.camera_zoom_speed; let z = s / (s - delta); let m = Matrix4f::translate(input_state.mouse_pos) * Matrix4f::scale(z) * Matrix4f::translate(-input_state.mouse_pos); camera .update_with(move |v| m * v) .error("Error while zooming camera"); } MouseEvent::Delta(x, y) if input_state.button_state(&[MouseButton::Right]) => { let m = Matrix4f::translate((*x, -*y, 0.0)); camera .update_with(move |v| m * v) .error("Error while zooming camera"); } MouseEvent::ButtonDown(b) if b == &config.input.camera_move_button => { control_events.single_write(ControlEvent::LockMouse); } MouseEvent::ButtonUp(b) if b == &config.input.camera_move_button => { control_events.single_write(ControlEvent::UnlockMouse); } _ => (), } } /* move camera */ let up = input_state.key_state(&config.input.camera_move_key_up); let down = input_state.key_state(&config.input.camera_move_key_down); let left = input_state.key_state(&config.input.camera_move_key_left); let right = input_state.key_state(&config.input.camera_move_key_right); if up || down || left || right { let s = config.input.camera_move_speed * global.delta; let translate = Vector3f::new( if left { s } else { 0.0 } + if right { -s } else { 0.0 }, if up { -s } else { 0.0 } + if down { s } else { 0.0 }, 0.0, ); let m = Matrix4f::translate(translate); camera .update_with(move |v| m * v) .error("Error while moving camera"); } uniform .update() .error("Error while updating global uniform data"); /* render background */ self.program.bind(); geometry.render_quad(); self.program.unbind(); } }