pub mod gl;
#[cfg(feature = "min_timer")]
pub mod now;
use glfw::{Context, Glfw, Monitor, SwapInterval, Window, WindowEvent};
use std::sync::mpsc::Receiver;
pub struct Options {
pub width: u32,
pub height: u32,
pub title: String,
pub fullscreen: bool,
pub decorated: bool,
pub msaa: Option<u32>,
pub vsync: bool,
}
impl Options {
fn config(&self, glfw: &mut Glfw) {
use glfw::WindowHint::*;
glfw.default_window_hints();
glfw.window_hint(Resizable(false));
glfw.window_hint(Decorated(self.decorated));
glfw.window_hint(Samples(self.msaa));
glfw.window_hint(ContextVersion(4, 6));
glfw.window_hint(OpenGlForwardCompat(true));
glfw.window_hint(OpenGlProfile(glfw::OpenGlProfileHint::Core));
#[cfg(debug_assertions)]
glfw.window_hint(OpenGlDebugContext(true));
}
fn create(&self, glfw: &mut Glfw, monitor: &Monitor) -> (Window, Receiver<(f64, WindowEvent)>) {
let (mut window, events) = glfw
.create_window(
self.width,
self.height,
self.title.as_str(),
if self.fullscreen {
glfw::WindowMode::FullScreen(monitor)
} else {
glfw::WindowMode::Windowed
},
)
.expect("Could not create the window!");
let vidmode = monitor
.get_video_mode()
.expect("Could not get the vidmode of the monitor!");
window.set_pos(
(vidmode.width - self.width) as i32 / 2,
(vidmode.height - self.height) as i32 / 2,
);
window.set_cursor_pos(self.width as f64 / 2.0, self.height as f64 / 2.0);
(window, events)
}
fn config_context(&self, glfw: &mut Glfw) {
glfw.set_swap_interval(SwapInterval::Sync(self.vsync as u32));
gl::Viewport(0, 0, self.width as i32, self.height as i32);
match self.msaa {
Some(_) => gl::Enable(gl::MULTISAMPLE),
None => gl::Disable(gl::MULTISAMPLE),
}
}
}
pub struct Display<T: FnMut(WindowEvent)> {
window: Window,
handler: T,
events: Receiver<(f64, WindowEvent)>,
}
impl<T: FnMut(WindowEvent)> Display<T> {
pub fn new(opt: Options, handler: T) -> Self {
let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).expect("Could not initialize the GLFW!");
let (mut window, events) = glfw.with_primary_monitor(|glfw, monitor| {
if let Some(monitor) = monitor {
opt.config(glfw);
opt.create(glfw, monitor)
} else {
panic!("Could not get the primary monitor!");
}
});
window.set_all_polling(true);
window.make_current();
gl::load(|proc| glfw.get_proc_address_raw(proc));
opt.config_context(&mut glfw);
Self {
window,
handler,
events,
}
}
pub fn render(&mut self) {
self.window.swap_buffers();
gl::Clear(gl::COLOR_BUFFER_BIT);
}
pub fn update(&mut self) {
self.glfw_mut().poll_events();
for (_, event) in glfw::flush_messages(&self.events) {
(self.handler)(event);
}
}
pub fn window(&self) -> &Window {
&self.window
}
pub fn glfw(&self) -> &Glfw {
&self.window().glfw
}
pub fn window_mut(&mut self) -> &mut Window {
&mut self.window
}
pub fn glfw_mut(&mut self) -> &mut Glfw {
&mut self.window_mut().glfw
}
}
#[cfg(test)]
mod tests {
use glfw::WindowEvent;
use crate::{gl, Display, Options};
#[test]
#[ignore]
fn window_with_event_logging() {
let mut event_count = 0u32;
let mut disp = Display::new(
Options {
width: 1280,
height: 720,
title: "Display Test".into(),
fullscreen: false,
decorated: true,
msaa: Some(16),
vsync: true,
},
|event| {
event_count += 1;
match event {
WindowEvent::Key(k, _, a, _) => println!("Key `{:?}` is {:?}ed!", k, a),
e => println!("Some {:?} happened!", e),
}
},
);
while !disp.window().should_close() {
disp.update();
gl::ClearColor(0.7, 0.5, 0.6, 1.0);
disp.render();
}
println!("In total {} window events happened!", event_count);
}
}