mirror of
https://github.com/italicsjenga/mini_gl_fb.git
synced 2024-11-25 08:51:31 +11:00
Add support for basic input handling without breakout
This commit is contained in:
parent
41fcc99608
commit
0d4e6a9822
|
@ -1,8 +1,71 @@
|
|||
use glutin::{GlWindow, EventsLoop};
|
||||
use glutin::{
|
||||
GlWindow,
|
||||
EventsLoop,
|
||||
VirtualKeyCode,
|
||||
MouseButton,
|
||||
ModifiersState,
|
||||
};
|
||||
use core::Framebuffer;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct GlutinBreakout {
|
||||
pub events_loop: EventsLoop,
|
||||
pub gl_window: GlWindow,
|
||||
pub fb: Framebuffer,
|
||||
}
|
||||
|
||||
pub struct BasicInput {
|
||||
/// The mouse position in buffer coordinates
|
||||
pub mouse_pos: (usize, usize),
|
||||
/// Stores whether a mouse button was down and is down, in that order.
|
||||
///
|
||||
/// If a button has not been pressed yet it will not be in the map.
|
||||
pub mouse: HashMap<MouseButton, (bool, bool)>,
|
||||
/// Stores the previous and current "key down" states, in that order.
|
||||
///
|
||||
/// If a key has not been pressed yet it will not be in the map.
|
||||
pub keys: HashMap<VirtualKeyCode, (bool, bool)>,
|
||||
pub modifiers: ModifiersState,
|
||||
pub resized: bool,
|
||||
}
|
||||
|
||||
impl BasicInput {
|
||||
/// If the mouse was pressed this last frame.
|
||||
pub fn mouse_pressed(&self, button: MouseButton) -> bool {
|
||||
&(false, true) == self.mouse.get(&button).unwrap_or(&(false, false))
|
||||
}
|
||||
|
||||
/// If the mouse is currently down.
|
||||
pub fn mouse_is_down(&self, button: MouseButton) -> bool {
|
||||
if let &(_, true) = self.mouse.get(&button).unwrap_or(&(false, false)) {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// If the mouse was released this last frame.
|
||||
pub fn mouse_released(&self, button: MouseButton) -> bool {
|
||||
&(true, false) == self.mouse.get(&button).unwrap_or(&(false, false))
|
||||
}
|
||||
|
||||
/// If the key was pressed this last frame.
|
||||
pub fn key_pressed(&self, button: VirtualKeyCode) -> bool {
|
||||
&(false, true) == self.keys.get(&button).unwrap_or(&(false, false))
|
||||
}
|
||||
|
||||
/// If the key is currently down.
|
||||
pub fn key_is_down(&self, button: VirtualKeyCode) -> bool {
|
||||
if let &(_, true) = self.keys.get(&button).unwrap_or(&(false, false)) {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// If the key was released this last frame.
|
||||
pub fn key_released(&self, button: VirtualKeyCode) -> bool {
|
||||
&(true, false) == self.keys.get(&button).unwrap_or(&(false, false))
|
||||
}
|
||||
}
|
||||
|
|
85
src/core.rs
85
src/core.rs
|
@ -1,4 +1,4 @@
|
|||
use breakout::GlutinBreakout;
|
||||
use breakout::{GlutinBreakout, BasicInput};
|
||||
|
||||
use rustic_gl;
|
||||
|
||||
|
@ -13,12 +13,13 @@ use glutin::{
|
|||
VirtualKeyCode,
|
||||
ElementState,
|
||||
};
|
||||
use glutin::dpi::LogicalSize;
|
||||
use glutin::dpi::{LogicalSize, LogicalPosition};
|
||||
|
||||
use gl;
|
||||
use gl::types::*;
|
||||
|
||||
use std::mem::size_of_val;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Create a context using glutin given a configuration.
|
||||
pub fn init_glutin_context<S: ToString>(
|
||||
|
@ -132,6 +133,7 @@ pub fn init_framebuffer(
|
|||
vao,
|
||||
vbo,
|
||||
texture_format,
|
||||
did_draw: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -242,6 +244,83 @@ impl Internal {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn glutin_handle_basic_input<F: FnMut(&mut Framebuffer, &BasicInput) -> bool>(
|
||||
&mut self, mut handler: F
|
||||
) {
|
||||
let mut running = true;
|
||||
let mut input = BasicInput {
|
||||
// Not sure how to set mouse pos at start
|
||||
mouse_pos: (0, 0),
|
||||
mouse: HashMap::new(),
|
||||
keys: HashMap::new(),
|
||||
modifiers: Default::default(),
|
||||
resized: false,
|
||||
};
|
||||
while running {
|
||||
let mut new_size = None;
|
||||
let mut new_mouse_pos: Option<LogicalPosition> = None;
|
||||
self.events_loop.poll_events(|event| {
|
||||
// Copy the current states into the previous state for input
|
||||
for (_, val) in &mut input.keys {
|
||||
val.0 = val.1;
|
||||
}
|
||||
for (_, val) in &mut input.mouse {
|
||||
val.0 = val.1;
|
||||
}
|
||||
match event {
|
||||
Event::WindowEvent { event, .. } => match event {
|
||||
WindowEvent::CloseRequested => running = false,
|
||||
WindowEvent::KeyboardInput { input: event_input, .. } => {
|
||||
if let Some(vk) = event_input.virtual_keycode {
|
||||
let key = input.keys.entry(vk)
|
||||
.or_insert((false, false));
|
||||
key.1 = event_input.state == ElementState::Pressed;
|
||||
}
|
||||
input.modifiers = event_input.modifiers;
|
||||
}
|
||||
WindowEvent::CursorMoved { position, modifiers, ..} => {
|
||||
new_mouse_pos = Some(position);
|
||||
input.modifiers = modifiers;
|
||||
}
|
||||
WindowEvent::MouseInput { state, button, modifiers, .. } => {
|
||||
let button = input.mouse.entry(button)
|
||||
.or_insert((false, false));
|
||||
button.1 = state == ElementState::Pressed;
|
||||
input.modifiers = modifiers;
|
||||
}
|
||||
WindowEvent::Resized(logical_size) => {
|
||||
new_size = Some(logical_size);
|
||||
}
|
||||
_ => {},
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
});
|
||||
if let Some(size) = new_size {
|
||||
let dpi_factor = self.gl_window.get_hidpi_factor();
|
||||
let (x, y) = size.to_physical(dpi_factor).into();
|
||||
self.resize_viewport(x, y);
|
||||
input.resized = false;
|
||||
}
|
||||
if let Some(pos) = new_mouse_pos {
|
||||
let dpi_factor = self.gl_window.get_hidpi_factor();
|
||||
let (x, y): (f64, f64) = pos.to_physical(dpi_factor).into();
|
||||
let x_scale = self.fb.buffer_width as f64 / (self.fb.vp_width as f64);
|
||||
let y_scale = self.fb.buffer_height as f64 / (self.fb.vp_height as f64);
|
||||
let mouse_pos = ((x * x_scale).floor() as usize, (y * y_scale).floor() as usize);
|
||||
input.mouse_pos = mouse_pos;
|
||||
}
|
||||
|
||||
if running {
|
||||
running = handler(&mut self.fb, &input);
|
||||
if self.fb.did_draw {
|
||||
self.gl_window.swap_buffers().unwrap();
|
||||
self.fb.did_draw = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn glutin_breakout(self) -> GlutinBreakout {
|
||||
GlutinBreakout {
|
||||
events_loop: self.events_loop,
|
||||
|
@ -278,6 +357,7 @@ pub struct Framebuffer {
|
|||
pub vao: GLuint,
|
||||
pub vbo: GLuint,
|
||||
pub texture_format: (BufferFormat, GLenum),
|
||||
pub did_draw: bool,
|
||||
}
|
||||
|
||||
impl Framebuffer {
|
||||
|
@ -375,6 +455,7 @@ impl Framebuffer {
|
|||
gl::BindVertexArray(0);
|
||||
gl::UseProgram(0);
|
||||
}
|
||||
self.did_draw = true;
|
||||
}
|
||||
|
||||
pub fn relink_program(&mut self) {
|
||||
|
|
23
src/lib.rs
23
src/lib.rs
|
@ -72,9 +72,9 @@ pub mod config;
|
|||
pub mod core;
|
||||
pub mod breakout;
|
||||
|
||||
pub use breakout::GlutinBreakout;
|
||||
pub use breakout::{GlutinBreakout, BasicInput};
|
||||
pub use config::Config;
|
||||
pub use core::{Internal, BufferFormat};
|
||||
pub use core::{Internal, BufferFormat, Framebuffer};
|
||||
|
||||
use core::ToGlType;
|
||||
|
||||
|
@ -304,6 +304,25 @@ impl MiniGlFb {
|
|||
self.internal.persist_and_redraw(redraw);
|
||||
}
|
||||
|
||||
/// Provides an easy interface for rudimentary input handling.
|
||||
///
|
||||
/// Automatically handles close events and partially handles resizes (the caller chooses if
|
||||
/// a redraw is necessary).
|
||||
///
|
||||
/// Polls for window events and summarizes the input events for you each frame. See
|
||||
/// `BasicInput` for the information that is provided to you. You will need to use some
|
||||
/// glutin types (which just wraps the crate winit's input types), so glutin is re-expoted
|
||||
/// by this library. You can access it via `use mini_gl_fb::glutin`.
|
||||
///
|
||||
/// You can cause the handler to exit by returning false from it. This does not kill the
|
||||
/// window, so as long as you still have it in scope, you can actually keep using it and,
|
||||
/// for example, resume handling input but with a different handler callback.
|
||||
pub fn glutin_handle_basic_input<F: FnMut(&mut Framebuffer, &BasicInput) -> bool>(
|
||||
&mut self, handler: F
|
||||
) {
|
||||
self.internal.glutin_handle_basic_input(handler);
|
||||
}
|
||||
|
||||
/// Need full access to Glutin's event handling? No problem!
|
||||
///
|
||||
/// Hands you the event loop and the window we created, so you can handle events however you
|
||||
|
|
Loading…
Reference in a new issue