Ver a proveniência

Implemented mouse and keyboard events and simple camera movement

raster
Bergmann89 há 5 anos
ascendente
cometimento
9263fd7895
13 ficheiros alterados com 334 adições e 65 eliminações
  1. +6
    -15
      glc/src/matrix.rs
  2. +12
    -0
      glc/src/vector.rs
  3. +1
    -1
      space-crush/Cargo.toml
  4. +5
    -15
      space-crush/resources/shader/noise.frag
  5. +3
    -3
      space-crush/resources/shader/quad.vert
  6. +10
    -3
      space-crush/resources/shader/text.vert
  7. +99
    -5
      space-crush/src/app/misc/events.rs
  8. +1
    -1
      space-crush/src/app/misc/mod.rs
  9. +1
    -0
      space-crush/src/app/misc/window.rs
  10. +78
    -10
      space-crush/src/app/render/init.rs
  11. +26
    -6
      space-crush/src/app/resources/camera.rs
  12. +40
    -1
      space-crush/src/app/resources/state.rs
  13. +52
    -5
      space-crush/src/app/systems/state_update.rs

+ 6
- 15
glc/src/matrix.rs Ver ficheiro

@@ -1,5 +1,6 @@
#![allow(dead_code)]

use std::borrow::Borrow;
use std::convert::{AsMut, AsRef};
use std::fmt::{Debug, Formatter, Result as FmtResult};
use std::ops::{Deref, DerefMut, Mul};
@@ -432,7 +433,7 @@ where
Matrix4::new(
Vector4::new(two / (right - left), zero, zero, zero),
Vector4::new(zero, two / (top - bottom), zero, zero),
Vector4::new(zero, zero, -zero / (far - near), zero),
Vector4::new(zero, zero, -two / (far - near), zero),
Vector4::new(
-(right + left) / (right - left),
-(top + bottom) / (top - bottom),
@@ -467,25 +468,15 @@ where
}
}

impl<T> Mul<Matrix4<T>> for Matrix4<T>
impl<T, M> Mul<M> for Matrix4<T>
where
T: Element,
M: Borrow<Matrix4<T>>,
{
type Output = Self;

fn mul(self, rhs: Self) -> Self::Output {
self.multiply(&rhs)
}
}

impl<T> Mul<Vector4<T>> for Matrix4<T>
where
T: Element,
{
type Output = Vector4<T>;

fn mul(self, rhs: Vector4<T>) -> Self::Output {
self.transform(&rhs)
fn mul(self, rhs: M) -> Self::Output {
self.multiply(rhs.borrow())
}
}



+ 12
- 0
glc/src/vector.rs Ver ficheiro

@@ -135,6 +135,18 @@ macro_rules! define_vec {
}
}

impl<T> From<T> for $Name<T>
where
T: Copy,
{
#[inline]
fn from(value: T) -> Self {
Self {
$($f: value,)+
}
}
}

impl<T> From<($($T,)+)> for $Name<T> {
#[inline]
fn from(($($f,)+): ($($T,)+)) -> Self {


+ 1
- 1
space-crush/Cargo.toml Ver ficheiro

@@ -16,7 +16,7 @@ num_cpus = "1.13"
ordered-float = "2.0"
rand = "0.7"
serde_yaml = "0.8"
shred = "0.10"
shred = { version = "0.10", features = [ "shred-derive" ] }
shrev = "1.1"
specs = "0.16"
thiserror = "1.0"


+ 5
- 15
space-crush/resources/shader/noise.frag Ver ficheiro

@@ -1,27 +1,17 @@
#version 450 core

in vec4 gl_FragCoord;

layout (std140, binding = 0) uniform Camera {
mat4 proj_world;
mat4 proj_ui;
mat4 view;
} camera;

out vec4 color;

const float NOISE_RANGE = 0.05;
const float NOISE_BASE = 0.05;

float random (vec2 st) {
return fract(sin(dot(st.xy, vec2(12.9898,78.233))) * 43758.5453123);
float random(vec4 seed) {
return fract(sin(dot(seed, vec4(12.9898, 78.233, 45.164, 53.1324))) * 43758.5453);
}

void main() {
vec4 pos = inverse(camera.view) * gl_FragCoord;

vec2 ipos = floor(pos.xy);
vec3 rbg = vec3(NOISE_BASE + NOISE_RANGE * random(ipos));
float rnd = random(gl_FragCoord);
vec3 rgb = vec3(NOISE_BASE + NOISE_RANGE * rnd);

color = vec4(rbg, 1.0);
color = vec4(rgb, 1.0);
}

+ 3
- 3
space-crush/resources/shader/quad.vert Ver ficheiro

@@ -3,9 +3,9 @@
layout (location = 0) in vec3 position;

layout (std140, binding = 0) uniform Camera {
mat4 proj_world;
mat4 proj_ui;
mat4 projection;
mat4 view;
vec2 size;
} camera;

layout (location = 1) uniform mat4 model;
@@ -16,5 +16,5 @@ out FragmentData {

void main() {
data.tex_coords = position.xy + vec2(0.5);
gl_Position = camera.proj_world * camera.view * model * vec4(position, 1.0);
gl_Position = camera.projection * camera.view * model * vec4(position, 1.0);
}

+ 10
- 3
space-crush/resources/shader/text.vert Ver ficheiro

@@ -7,9 +7,9 @@ layout (location = 3) in vec2 tex_max;
layout (location = 4) in vec4 color;

layout (std140, binding = 0) uniform Camera {
mat4 proj_world;
mat4 proj_ui;
mat4 projection;
mat4 view;
vec2 size;
} camera;

layout (location = 1) uniform mat4 model;
@@ -45,7 +45,14 @@ void main() {
break;
}

gl_Position = camera.proj_ui * vec4(position, 0.0, 1.0);
mat4 ortho = mat4(
vec4(2.0 / camera.size.x, 0.0, 0.0, 0.0),
vec4(0.0, -2.0 / camera.size.y, 0.0, 0.0),
vec4(0.0, 0.0, 1.0, 0.0),
vec4(-1.0, 1.0, 1.0, 1.0)
);

gl_Position = ortho * vec4(position, 0.0, 1.0);

data.tex_coord = tex_coord;
data.color = color;


+ 99
- 5
space-crush/src/app/misc/events.rs Ver ficheiro

@@ -1,20 +1,30 @@
use std::collections::HashSet;

use glutin::{
event::{Event, WindowEvent as GlutinWindowEvent},
event::{
ElementState, Event, KeyboardInput, MouseScrollDelta, WindowEvent as GlutinWindowEvent,
},
event_loop::{ControlFlow, EventLoop},
platform::desktop::EventLoopExtDesktop,
};
use shrev::EventChannel;
use specs::World;

pub use glutin::event::{MouseButton, VirtualKeyCode};

pub struct Events {
keys: HashSet<VirtualKeyCode>,
event_loop: EventLoop<()>,
}

impl Events {
pub fn new(world: &mut World) -> Self {
world.insert(EventChannel::<MouseEvent>::default());
world.insert(EventChannel::<WindowEvent>::default());
world.insert(EventChannel::<KeyboardEvent>::default());

Self {
keys: HashSet::new(),
event_loop: EventLoop::new(),
}
}
@@ -26,9 +36,14 @@ impl Events {
}

pub fn process(&mut self, world: &World) {
let mut channel = world.fetch_mut::<EventChannel<WindowEvent>>();
let mut mouse_events = world.fetch_mut::<EventChannel<MouseEvent>>();
let mut window_events = world.fetch_mut::<EventChannel<WindowEvent>>();
let mut keyboard_events = world.fetch_mut::<EventChannel<KeyboardEvent>>();

let keys = &mut self.keys;
let event_loop = &mut self.event_loop;

self.event_loop.run_return(|event, _target, flow_control| {
event_loop.run_return(|event, _target, flow_control| {
*flow_control = ControlFlow::Poll;

match event {
@@ -36,12 +51,77 @@ impl Events {
*flow_control = ControlFlow::Exit;
}
Event::WindowEvent { event, .. } => match event {
/* Mouse Events */
GlutinWindowEvent::CursorMoved { position, .. } => {
mouse_events
.single_write(MouseEvent::Move(position.x as _, position.y as _));
}
GlutinWindowEvent::MouseInput {
state: ElementState::Pressed,
button,
..
} => {
mouse_events.single_write(MouseEvent::ButtonDown(button));
}
GlutinWindowEvent::MouseInput {
state: ElementState::Released,
button,
..
} => {
mouse_events.single_write(MouseEvent::ButtonUp(button));
}
GlutinWindowEvent::MouseWheel {
delta: MouseScrollDelta::LineDelta(x, y),
..
} => {
if x != 0.0 {
mouse_events.single_write(MouseEvent::ScrollX(x));
}

if y != 0.0 {
mouse_events.single_write(MouseEvent::ScrollY(y));
}
}

/* Key Event */
GlutinWindowEvent::KeyboardInput {
input:
KeyboardInput {
state: ElementState::Pressed,
virtual_keycode: Some(key),
..
},
..
} => {
if keys.insert(key) {
keyboard_events.single_write(KeyboardEvent::KeyDown(key));
}

keyboard_events.single_write(KeyboardEvent::KeyPress(key));
}
GlutinWindowEvent::KeyboardInput {
input:
KeyboardInput {
state: ElementState::Released,
virtual_keycode: Some(key),
..
},
..
} => {
if keys.remove(&key) {
keyboard_events.single_write(KeyboardEvent::KeyUp(key));
}
}

/* Window Event */
GlutinWindowEvent::Resized(pos) => {
channel.single_write(WindowEvent::Resize(pos.width, pos.height));
window_events.single_write(WindowEvent::Resize(pos.width, pos.height));
}
GlutinWindowEvent::CloseRequested => {
channel.single_write(WindowEvent::Close);
window_events.single_write(WindowEvent::Close);
}

/* Ignore */
_ => (),
},
_ => (),
@@ -54,3 +134,17 @@ pub enum WindowEvent {
Resize(u32, u32),
Close,
}

pub enum MouseEvent {
Move(f32, f32),
ButtonDown(MouseButton),
ButtonUp(MouseButton),
ScrollX(f32),
ScrollY(f32),
}

pub enum KeyboardEvent {
KeyUp(VirtualKeyCode),
KeyDown(VirtualKeyCode),
KeyPress(VirtualKeyCode),
}

+ 1
- 1
space-crush/src/app/misc/mod.rs Ver ficheiro

@@ -3,7 +3,7 @@ mod text;
mod window;
mod world;

pub use events::{Events, WindowEvent};
pub use events::{Events, KeyboardEvent, MouseButton, MouseEvent, VirtualKeyCode, WindowEvent};
pub use text::{Text, TextCache, TextManager};
pub use window::Window;
pub use world::WorldHelper;

+ 1
- 0
space-crush/src/app/misc/window.rs Ver ficheiro

@@ -56,6 +56,7 @@ impl Window {

gl::disable(gl::CULL_FACE);
gl::disable(gl::DEPTH_TEST);
gl::clear_color(0.1, 0.1, 0.1, 1.0);
gl::pixel_store_i(gl::UNPACK_ALIGNMENT, 1);

Ok(Self { context })


+ 78
- 10
space-crush/src/app/render/init.rs Ver ficheiro

@@ -1,20 +1,24 @@
use glc::{
matrix::Matrix4f,
misc::Bindable,
shader::{Program, Type},
vector::Vector3f,
};
use log::error;
use specs::{ReadExpect, System, World, WriteExpect};
use shrev::{EventChannel, ReaderId};
use specs::{prelude::*, ReadExpect, System, World, WriteExpect};

use crate::Error;

use super::super::{
misc::WorldHelper,
misc::{MouseEvent, VirtualKeyCode, WorldHelper},
resources::{Camera, Geometry, State},
};

pub struct Init {
program: Program,
resolution: (u32, u32),
mouse_event_id: ReaderId<MouseEvent>,
}

impl Init {
@@ -23,22 +27,37 @@ impl Init {
(Type::Vertex, "resources/shader/noise.vert"),
(Type::Fragment, "resources/shader/noise.frag"),
])?;
let resolution = (0, 0);
let mouse_event_id = world.register_event_reader::<MouseEvent>()?;

Ok(Self {
program,
resolution: (0, 0),
resolution,
mouse_event_id,
})
}
}

#[derive(SystemData)]
pub struct InitData<'a> {
camera: WriteExpect<'a, Camera>,
state: ReadExpect<'a, State>,
geometry: ReadExpect<'a, Geometry>,
mouse_events: ReadExpect<'a, EventChannel<MouseEvent>>,
}

impl<'a> System<'a> for Init {
type SystemData = (
WriteExpect<'a, Camera>,
ReadExpect<'a, State>,
ReadExpect<'a, Geometry>,
);
type SystemData = InitData<'a>;

fn run(&mut self, (mut camera, state, geometry): Self::SystemData) {
fn run(&mut self, data: Self::SystemData) {
let InitData {
mut camera,
state,
geometry,
mouse_events,
} = data;

/* screen size */
if self.resolution != state.resolution {
self.resolution = state.resolution;

@@ -46,12 +65,61 @@ impl<'a> System<'a> for Init {

if let Err(err) = camera.resize(self.resolution.0 as _, self.resolution.1 as _) {
error!("Error while updating camera: {}", err);
panic!("Error while updating camera: {}", err);
}
}

/* zoom */
let events = mouse_events.read(&mut self.mouse_event_id);
for event in events {
if let MouseEvent::ScrollY(delta) = event {
let z = CAMERA_ZOOM_SPEED / (CAMERA_ZOOM_SPEED - delta);
let m = Matrix4f::translate((state.mouse_pos.0, state.mouse_pos.1, 0.0).into())
* Matrix4f::scale(z.into())
* Matrix4f::translate((-state.mouse_pos.0, -state.mouse_pos.1, 0.0).into());

if let Err(err) = camera.update_with(move |v| m * v) {
error!("Error while zooming camera: {}", err);
}
}
}

/* move camera */
let up = state.key_state(KEY_CAMERA_UP) || state.key_state(KEY_CAMERA_UP_ALT);
let down = state.key_state(KEY_CAMERA_DOWN) || state.key_state(KEY_CAMERA_DOWN_ALT);
let left = state.key_state(KEY_CAMERA_LEFT) || state.key_state(KEY_CAMERA_LEFT_ALT);
let right = state.key_state(KEY_CAMERA_RIGHT) || state.key_state(KEY_CAMERA_RIGHT_ALT);

let translate = Vector3f::new(
if left { CAMERA_MOVE_SPEED_KEY } else { 0.0 }
+ if right { -CAMERA_MOVE_SPEED_KEY } else { 0.0 },
if up { -CAMERA_MOVE_SPEED_KEY } else { 0.0 }
+ if down { CAMERA_MOVE_SPEED_KEY } else { 0.0 },
0.0,
);

if up || down || left || right {
let m = Matrix4f::translate(translate);
if let Err(err) = camera.update_with(move |v| m * v) {
error!("Error while moving camera: {}", err);
}
}

/* render background */
self.program.bind();
geometry.render_quad();
self.program.unbind();
}
}

const CAMERA_MOVE_SPEED_KEY: f32 = 2.0;
const CAMERA_ZOOM_SPEED: f32 = 100.0;

const KEY_CAMERA_UP: VirtualKeyCode = VirtualKeyCode::Up;
const KEY_CAMERA_DOWN: VirtualKeyCode = VirtualKeyCode::Down;
const KEY_CAMERA_LEFT: VirtualKeyCode = VirtualKeyCode::Left;
const KEY_CAMERA_RIGHT: VirtualKeyCode = VirtualKeyCode::Right;

const KEY_CAMERA_UP_ALT: VirtualKeyCode = VirtualKeyCode::W;
const KEY_CAMERA_DOWN_ALT: VirtualKeyCode = VirtualKeyCode::S;
const KEY_CAMERA_LEFT_ALT: VirtualKeyCode = VirtualKeyCode::A;
const KEY_CAMERA_RIGHT_ALT: VirtualKeyCode = VirtualKeyCode::D;

+ 26
- 6
space-crush/src/app/resources/camera.rs Ver ficheiro

@@ -4,6 +4,7 @@ use glc::{
array_buffer::{ArrayBuffer, Target, Usage},
error::Error,
matrix::Matrix4f,
vector::Vector2f,
};

pub struct Camera {
@@ -16,9 +17,9 @@ impl Camera {
buffer.buffer_data(
Usage::StaticDraw,
&[Data {
proj_world: Matrix4f::identity(),
proj_ui: Matrix4f::identity(),
projection: Matrix4f::identity(),
view: Matrix4f::identity(),
size: Vector2f::default(),
}],
)?;

@@ -28,8 +29,27 @@ impl Camera {
pub fn resize(&mut self, w: f32, h: f32) -> Result<(), Error> {
let mut data = self.buffer.map_mut::<Data>(true)?;

data[0].proj_world = Matrix4f::ortho(-w / 2.0, w / 2.0, -h / 2.0, h / 2.0, -100.0, 100.0);
data[0].proj_ui = Matrix4f::ortho(0.0, w, h, 0.0, -100.0, 100.0);
data[0].projection = Matrix4f::ortho(-w / 2.0, w / 2.0, -h / 2.0, h / 2.0, -100.0, 100.0);
data[0].size = (w, h).into();

Ok(())
}

pub fn update(&mut self, view: Matrix4f) -> Result<(), Error> {
let mut data = self.buffer.map_mut::<Data>(true)?;

data[0].view = data[0].view * view;

Ok(())
}

pub fn update_with<F>(&mut self, f: F) -> Result<(), Error>
where
F: FnOnce(&Matrix4f) -> Matrix4f,
{
let mut data = self.buffer.map_mut::<Data>(true)?;

data[0].view = f(&data[0].view);

Ok(())
}
@@ -41,7 +61,7 @@ impl Camera {

#[repr(C, packed)]
struct Data {
proj_world: Matrix4f,
proj_ui: Matrix4f,
projection: Matrix4f,
view: Matrix4f,
size: Vector2f,
}

+ 40
- 1
space-crush/src/app/resources/state.rs Ver ficheiro

@@ -1,6 +1,45 @@
#![allow(dead_code)]

use std::collections::HashSet;

use super::super::misc::{MouseButton, VirtualKeyCode};

#[derive(Default)]
pub struct State {
pub mouse_pos: (f32, f32),
pub resolution: (u32, u32),

pub close_requested: bool,
pub key_states: HashSet<KeyState>,
}

#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum KeyState {
KeyCode(VirtualKeyCode),
MouseButton(MouseButton),
}

impl State {
pub fn key_state(&self, code: VirtualKeyCode) -> bool {
self.key_states.contains(&KeyState::KeyCode(code))
}

pub fn button_state(&self, button: MouseButton) -> bool {
self.key_states.contains(&KeyState::MouseButton(button))
}

pub fn set_key_state(&mut self, code: VirtualKeyCode, value: bool) {
if value {
self.key_states.insert(KeyState::KeyCode(code));
} else {
self.key_states.remove(&KeyState::KeyCode(code));
}
}

pub fn set_button_state(&mut self, button: MouseButton, value: bool) {
if value {
self.key_states.insert(KeyState::MouseButton(button));
} else {
self.key_states.remove(&KeyState::MouseButton(button));
}
}
}

+ 52
- 5
space-crush/src/app/systems/state_update.rs Ver ficheiro

@@ -1,29 +1,67 @@
use shrev::{EventChannel, ReaderId};
use specs::{ReadExpect, System, World, Write};
use specs::{prelude::*, ReadExpect, System, World, Write};

use crate::Error;

use super::super::{
misc::{WindowEvent, WorldHelper},
misc::{KeyboardEvent, MouseEvent, WindowEvent, WorldHelper},
resources::State,
};

pub struct StateUpdate {
mouse_event_id: ReaderId<MouseEvent>,
window_events_id: ReaderId<WindowEvent>,
keyboard_events_id: ReaderId<KeyboardEvent>,
}

impl StateUpdate {
pub fn new(world: &mut World) -> Result<Self, Error> {
let mouse_event_id = world.register_event_reader::<MouseEvent>()?;
let window_events_id = world.register_event_reader::<WindowEvent>()?;
let keyboard_events_id = world.register_event_reader::<KeyboardEvent>()?;

Ok(Self { window_events_id })
Ok(Self {
mouse_event_id,
window_events_id,
keyboard_events_id,
})
}
}

#[derive(SystemData)]
pub struct StateUpdateData<'a> {
state: Write<'a, State>,
mouse_events: ReadExpect<'a, EventChannel<MouseEvent>>,
window_events: ReadExpect<'a, EventChannel<WindowEvent>>,
keyboard_events: ReadExpect<'a, EventChannel<KeyboardEvent>>,
}

impl<'a> System<'a> for StateUpdate {
type SystemData = (Write<'a, State>, ReadExpect<'a, EventChannel<WindowEvent>>);
type SystemData = StateUpdateData<'a>;

fn run(&mut self, data: Self::SystemData) {
let StateUpdateData {
mut state,
mouse_events,
window_events,
keyboard_events,
} = data;

let events = mouse_events.read(&mut self.mouse_event_id);
for event in events {
match event {
MouseEvent::Move(x, y) => {
let x = *x - state.resolution.0 as f32 / 2.0;
let y = state.resolution.1 as f32 / 2.0 - *y;

state.mouse_pos = (x, y);
}
MouseEvent::ButtonUp(button) => state.set_button_state(*button, false),
MouseEvent::ButtonDown(button) => state.set_button_state(*button, true),
_ => (),
}
}

fn run(&mut self, (mut state, window_events): Self::SystemData) {
let events = window_events.read(&mut self.window_events_id);
for event in events {
match event {
@@ -35,5 +73,14 @@ impl<'a> System<'a> for StateUpdate {
}
}
}

let events = keyboard_events.read(&mut self.keyboard_events_id);
for event in events {
match event {
KeyboardEvent::KeyUp(code) => state.set_key_state(*code, false),
KeyboardEvent::KeyDown(code) => state.set_key_state(*code, true),
_ => (),
}
}
}
}

Carregando…
Cancelar
Guardar