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 core::Framebuffer;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub struct GlutinBreakout {
|
pub struct GlutinBreakout {
|
||||||
pub events_loop: EventsLoop,
|
pub events_loop: EventsLoop,
|
||||||
pub gl_window: GlWindow,
|
pub gl_window: GlWindow,
|
||||||
pub fb: Framebuffer,
|
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;
|
use rustic_gl;
|
||||||
|
|
||||||
|
@ -13,12 +13,13 @@ use glutin::{
|
||||||
VirtualKeyCode,
|
VirtualKeyCode,
|
||||||
ElementState,
|
ElementState,
|
||||||
};
|
};
|
||||||
use glutin::dpi::LogicalSize;
|
use glutin::dpi::{LogicalSize, LogicalPosition};
|
||||||
|
|
||||||
use gl;
|
use gl;
|
||||||
use gl::types::*;
|
use gl::types::*;
|
||||||
|
|
||||||
use std::mem::size_of_val;
|
use std::mem::size_of_val;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
/// Create a context using glutin given a configuration.
|
/// Create a context using glutin given a configuration.
|
||||||
pub fn init_glutin_context<S: ToString>(
|
pub fn init_glutin_context<S: ToString>(
|
||||||
|
@ -132,6 +133,7 @@ pub fn init_framebuffer(
|
||||||
vao,
|
vao,
|
||||||
vbo,
|
vbo,
|
||||||
texture_format,
|
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 {
|
pub fn glutin_breakout(self) -> GlutinBreakout {
|
||||||
GlutinBreakout {
|
GlutinBreakout {
|
||||||
events_loop: self.events_loop,
|
events_loop: self.events_loop,
|
||||||
|
@ -278,6 +357,7 @@ pub struct Framebuffer {
|
||||||
pub vao: GLuint,
|
pub vao: GLuint,
|
||||||
pub vbo: GLuint,
|
pub vbo: GLuint,
|
||||||
pub texture_format: (BufferFormat, GLenum),
|
pub texture_format: (BufferFormat, GLenum),
|
||||||
|
pub did_draw: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Framebuffer {
|
impl Framebuffer {
|
||||||
|
@ -375,6 +455,7 @@ impl Framebuffer {
|
||||||
gl::BindVertexArray(0);
|
gl::BindVertexArray(0);
|
||||||
gl::UseProgram(0);
|
gl::UseProgram(0);
|
||||||
}
|
}
|
||||||
|
self.did_draw = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn relink_program(&mut self) {
|
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 core;
|
||||||
pub mod breakout;
|
pub mod breakout;
|
||||||
|
|
||||||
pub use breakout::GlutinBreakout;
|
pub use breakout::{GlutinBreakout, BasicInput};
|
||||||
pub use config::Config;
|
pub use config::Config;
|
||||||
pub use core::{Internal, BufferFormat};
|
pub use core::{Internal, BufferFormat, Framebuffer};
|
||||||
|
|
||||||
use core::ToGlType;
|
use core::ToGlType;
|
||||||
|
|
||||||
|
@ -304,6 +304,25 @@ impl MiniGlFb {
|
||||||
self.internal.persist_and_redraw(redraw);
|
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!
|
/// 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
|
/// Hands you the event loop and the window we created, so you can handle events however you
|
||||||
|
|
Loading…
Reference in a new issue