use rin_math::{Vec2, Pnt2, pnt2, vec2};
use rin_util as util;
use seitan::*;
use crate::CursorMode;
use super::{Events, KeyEvents, WindowExt, Key, Event, KeyModifiers, MouseButton};
use std::cell::RefCell;
use std::os::raw::{c_void, c_float, c_ushort, c_char, c_int};
use std::mem;
use std::slice;
use std::ffi::CStr;
use glfw::{self, Context};
use rin_util::Result;
use std::sync::Arc;
use parking_lot::{
RwLock, RwLockReadGuard, RwLockWriteGuard, MappedRwLockReadGuard, MappedRwLockWriteGuard
};
#[cfg(any(feature="gl", feature="gles"))]
use glin;
use std::time::{Duration, Instant};
pub use glfw::Key as GlfwKey;
use super::Cursor;
pub use glfw::{VidMode, GammaRamp};
pub mod key_mappings{
pub use glfw::Key::*;
}
static mut GLFW: Option<glfw::Glfw> = None;
struct EventsPollData {
glfw: glfw::Glfw,
should_close: u32,
}
#[derive(Clone)]
pub struct EventsPoll(Arc<RwLock<EventsPollData>>);
pub struct Monitor<'a> {
ptr: *mut glfw::ffi::GLFWmonitor,
glfw_guard: RwLockReadGuard<'a, EventsPollData>
}
pub unsafe fn string_from_c_str(c_str: *const c_char) -> String {
String::from_utf8_lossy(CStr::from_ptr(c_str).to_bytes()).into_owned()
}
fn from_glfw_vid_mode(mode: &glfw::ffi::GLFWvidmode) -> VidMode {
VidMode {
width: mode.width as u32,
height: mode.height as u32,
red_bits: mode.redBits as u32,
green_bits: mode.greenBits as u32,
blue_bits: mode.blueBits as u32,
refresh_rate: mode.refreshRate as u32,
}
}
#[inline(always)]
fn unwrap_dont_care(value: Option<u32>) -> c_int {
match value {
Some(v) => v as c_int,
None => glfw::ffi::DONT_CARE,
}
}
pub unsafe fn string_from_nullable_c_str(c_str: *const c_char) -> Option<String> {
if c_str.is_null() {
None
} else {
Some(string_from_c_str(c_str))
}
}
impl<'a> Monitor<'a> {
pub fn pos(&self) -> (i32, i32) {
unsafe {
let mut xpos = 0;
let mut ypos = 0;
glfw::ffi::glfwGetMonitorPos(self.ptr, &mut xpos, &mut ypos);
(xpos as i32, ypos as i32)
}
}
pub fn physical_size(&self) -> (i32, i32) {
unsafe {
let mut width = 0;
let mut height = 0;
glfw::ffi::glfwGetMonitorPhysicalSize(self.ptr, &mut width, &mut height);
(width as i32, height as i32)
}
}
pub fn name(&self) -> Option<String> {
unsafe { string_from_nullable_c_str(glfw::ffi::glfwGetMonitorName(self.ptr)) }
}
pub fn video_modes(&self) -> Vec<VidMode> {
unsafe {
let mut count = 0;
let ptr = glfw::ffi::glfwGetVideoModes(self.ptr, &mut count);
slice::from_raw_parts(ptr, count as usize)
.iter()
.map(from_glfw_vid_mode)
.collect()
}
}
pub fn video_mode(&self) -> Option<VidMode> {
unsafe {
let ptr = glfw::ffi::glfwGetVideoMode(self.ptr);
if ptr.is_null() {
None
} else {
Some(from_glfw_vid_mode(&*ptr))
}
}
}
pub fn set_gamma(&mut self, gamma: f32) {
unsafe {
glfw::ffi::glfwSetGamma(self.ptr, gamma as c_float);
}
}
pub fn gamma_ramp(&self) -> GammaRamp {
unsafe {
let llramp = *glfw::ffi::glfwGetGammaRamp(self.ptr);
GammaRamp {
red: slice::from_raw_parts(llramp.red as *const c_ushort, llramp.size as usize)
.iter()
.map(|&x| x)
.collect(),
green: slice::from_raw_parts(llramp.green as *const c_ushort, llramp.size as usize)
.iter()
.map(|&x| x)
.collect(),
blue: slice::from_raw_parts(llramp.blue as *const c_ushort, llramp.size as usize)
.iter()
.map(|&x| x)
.collect(),
}
}
}
pub fn set_gamma_ramp(&mut self, ramp: &mut GammaRamp) {
unsafe {
glfw::ffi::glfwSetGammaRamp(
self.ptr,
&glfw::ffi::GLFWgammaramp {
red: ramp.red.as_mut_ptr(),
green: ramp.green.as_mut_ptr(),
blue: ramp.blue.as_mut_ptr(),
size: ramp.red.len() as u32,
},
);
}
}
pub fn content_scale(&self) -> (f32, f32) {
unsafe {
let mut xscale = 0.0_f32;
let mut yscale = 0.0_f32;
glfw::ffi::glfwGetMonitorContentScale(self.ptr, &mut xscale, &mut yscale);
(xscale, yscale)
}
}
pub fn workarea(&self) -> (i32, i32, i32, i32) {
unsafe {
let mut xpos = 0;
let mut ypos = 0;
let mut width = 0;
let mut height = 0;
glfw::ffi::glfwGetMonitorWorkarea(self.ptr, &mut xpos, &mut ypos, &mut width, &mut height);
(xpos, ypos, width, height)
}
}
}
pub enum WindowMode<'a> {
FullScreen(Monitor<'a>),
Windowed
}
impl EventsPoll{
pub fn new() -> Result<EventsPoll>{
let glfw = unsafe{ if let Some(glfw) = GLFW.as_ref() {
glfw.clone()
}else{
let glfw = glfw::init(glfw::LOG_ERRORS)
.map_err(|e| rin_util::Error::with_cause("Error initializing glfw", e))?;
GLFW = Some(glfw.clone());
glfw
}};
Ok(EventsPoll( Arc::new( RwLock::new(EventsPollData{
glfw,
should_close: 1,
}))))
}
pub fn poll_events(&self){
self.0.write().glfw.poll_events()
}
pub fn wait_events(&self){
self.0.write().glfw.wait_events()
}
fn new_window(&mut self){
let mut data = self.0.write();
data.should_close += 1;
}
fn window_gone(&mut self){
let mut data = self.0.write();
data.should_close -=1;
if data.should_close == 1{
data.should_close = 0;
}
}
pub fn should_close(&self) -> bool{
self.0.write().should_close == 0
}
pub fn glfw(&self) -> MappedRwLockReadGuard<glfw::Glfw>{
RwLockReadGuard::map(self.0.read(), |data| &data.glfw)
}
pub fn glfw_mut(&mut self) -> MappedRwLockWriteGuard<glfw::Glfw>{
RwLockWriteGuard::map(self.0.write(), |data| &mut data.glfw)
}
pub fn primary_monitor(&self) -> Option<Monitor> {
match unsafe { glfw::ffi::glfwGetPrimaryMonitor() } {
ptr if ptr.is_null() => None,
ptr => Some(Monitor {
ptr: ptr,
glfw_guard: self.0.read()
}),
}
}
pub fn connected_monitors(&self) -> Vec<Monitor>{
unsafe {
let mut count = 0;
let ptr = glfw::ffi::glfwGetMonitors(&mut count);
slice::from_raw_parts(ptr as *const _, count as usize)
.iter()
.map(|&ptr| Monitor { ptr: ptr, glfw_guard: self.0.read() })
.collect()
}
}
}
pub struct Window{
glfw: EventsPoll,
glfw_window: glfw::Window,
curr_fps: f64,
frames: u64,
prev_time: Instant,
curr_frame_duration: Duration,
prev_frame_time: Instant,
total_frames: u64,
last_pos: (i32, i32),
last_size: (i32, i32),
esc_pressed: Property<'static, bool>,
events_sender: SenderFromReceiver<'static, (f64, glfw::WindowEvent)>,
update_sender: SenderRc<'static, Event>,
events_stream: StreamRc<'static, Event>,
swap_interval: glfw::SwapInterval,
}
pub struct Builder<'a>{
glfw: EventsPoll,
size: Option<(u32, u32)>,
title: String,
visible: bool,
resizable: bool,
#[cfg(any(feature="gl", feature="gles"))]
gl_version: (u32, u32),
fullscreen: bool,
samples: u32,
redbits: u32,
greenbits: u32,
bluebits: u32,
alphabits: u32,
depthbits: u32,
stencilbits: u32,
sticky_keys: bool,
swap_interval: glfw::SwapInterval,
shared_context: Option<&'a Window>,
position: Option<Pnt2<i32>>,
esc_closes: bool,
}
#[cfg(target_os="linux")]
struct WindowEventData{
display: *mut c_void,
_window: *mut c_void,
_xim: *mut c_void,
xic: *mut c_void,
}
#[cfg(target_os="macos")]
struct WindowEventData;
#[cfg(target_os="windows")]
struct WindowEventData;
impl WindowEventData{
#[cfg(target_os="linux")]
fn from(glfw: &glfw::Glfw, glfw_window: &glfw::Window) -> WindowEventData{
use window_platform::xlib::{XSetLocaleModifiers, XOpenIM, _XDisplay, XCreateIC, XNInputStyle};
use window_platform::xlib::{XIMPreeditNothing, XIMStatusNothing, XNClientWindow, XNFocusWindow };
use std::ffi::CString;
use std::ptr;
unsafe{
let display = glfw.get_x11_display() as *mut c_void;
let window = glfw_window.get_x11_window() as *mut c_void;
XSetLocaleModifiers(CString::new("").unwrap().as_ptr());
let mut xim = XOpenIM(display as *mut _XDisplay, ptr::null_mut(), ptr::null_mut(), ptr::null_mut());
if xim == ptr::null_mut() {
XSetLocaleModifiers(CString::new("@im=none").unwrap().as_ptr());
xim = XOpenIM(display as *mut _XDisplay, ptr::null_mut(), ptr::null_mut(), ptr::null_mut());
}
let xic = XCreateIC(xim,
CString::new(XNInputStyle).unwrap().as_ptr(), XIMPreeditNothing | XIMStatusNothing,
CString::new(XNClientWindow).unwrap().as_ptr(), window,
CString::new(XNFocusWindow).unwrap().as_ptr(), window,
ptr::null::<c_void>());
WindowEventData{
display,
_window: window,
_xim: xim as *mut c_void,
xic: xic as *mut c_void,
}
}
}
#[cfg(target_os="macos")]
fn from(glfw: &glfw::Glfw, glfw_window: &glfw::Window) -> WindowEventData{
WindowEventData
}
#[cfg(target_os="windows")]
fn from(glfw: &glfw::Glfw, glfw_window: &glfw::Window) -> WindowEventData{
WindowEventData
}
}
impl<'a> Builder<'a>{
pub fn new(events: EventsPoll) -> Builder<'a>{
Builder{
glfw: events,
size: None,
title: String::new(),
visible: true,
resizable: true,
fullscreen: false,
#[cfg(feature="gl")]
gl_version: (4,1),
#[cfg(feature="gles")]
gl_version: (3,0),
samples: 8,
redbits: 8,
greenbits: 8,
bluebits: 8,
alphabits: 8,
depthbits: 24,
stencilbits: 8,
sticky_keys: true,
swap_interval: glfw::SwapInterval::Sync(1),
shared_context: None,
esc_closes: true,
position: None,
}
}
pub fn size(&mut self, w: u32, h: u32) -> &mut Builder<'a>{
self.size = Some((w, h));
self
}
pub fn title(&mut self, title: &str) -> &mut Builder<'a>{
self.title = title.to_string();
self
}
pub fn visible(&mut self, visible: bool) -> &mut Builder<'a>{
self.visible = visible;
self
}
pub fn resizable(&mut self, resizable: bool) -> &mut Builder<'a>{
self.resizable = resizable;
self
}
#[cfg(any(feature="gl", feature="gles"))]
pub fn gl_version(&mut self, major: u32, minor: u32) -> &mut Builder<'a>{
self.gl_version = (major, minor);
self
}
pub fn samples(&mut self, samples: u32) -> &mut Builder<'a>{
self.samples = samples;
self
}
pub fn swap_interval(&mut self, frames: u32) -> &mut Builder<'a>{
if frames == 0 {
self.swap_interval = glfw::SwapInterval::None
}else{
self.swap_interval = glfw::SwapInterval::Sync(frames)
}
self
}
pub fn adaptative_swap_interval(&mut self) -> &mut Builder<'a>{
self.swap_interval = glfw::SwapInterval::Adaptive;
self
}
pub fn depth_bits(&mut self, depth_bits: u32) -> &mut Builder<'a>{
self.depthbits = depth_bits;
self
}
pub fn stencil_bits(&mut self, stencil_bits: u32) -> &mut Builder<'a>{
self.stencilbits = stencil_bits;
self
}
pub fn red_bits(&mut self, red_bits: u32) -> &mut Builder<'a>{
self.redbits = red_bits;
self
}
pub fn green_bits(&mut self, green_bits: u32) -> &mut Builder<'a>{
self.greenbits = green_bits;
self
}
pub fn blue_bits(&mut self, blue_bits: u32) -> &mut Builder<'a>{
self.bluebits = blue_bits;
self
}
pub fn share_context_with(&mut self, window: &'a Window) -> &mut Builder<'a>{
self.shared_context = Some(window);
self
}
pub fn esc_closes_window(&mut self, closes: bool) -> &mut Builder<'a>{
self.esc_closes = closes;
self
}
pub fn fullscreen(&mut self) -> &mut Builder<'a>{
self.fullscreen = true;
self
}
pub fn position(&mut self, pos: Pnt2<i32>) -> &mut Builder<'a>{
self.position = Some(pos);
self
}
pub fn build(&mut self) -> Result<Window>{
self.glfw.new_window();
let mut glfw = self.glfw.0.write();
let glfw = &mut glfw.glfw;
glfw.window_hint(glfw::WindowHint::Visible(self.visible && !self.position.is_some()));
if !self.fullscreen {
glfw.window_hint(glfw::WindowHint::Resizable(self.resizable));
}
#[cfg(feature="gles")]
{
glfw.window_hint(glfw::WindowHint::ClientApi(glfw::ClientApiHint::OpenGlEs));
glfw.window_hint(glfw::WindowHint::ContextCreationApi(glfw::ContextCreationApi::Native));
glfw.window_hint(glfw::WindowHint::ContextVersion(self.gl_version.0, self.gl_version.1));
}
#[cfg(feature="gl")]
{
glfw.window_hint(glfw::WindowHint::ClientApi(glfw::ClientApiHint::OpenGl));
glfw.window_hint(glfw::WindowHint::ContextCreationApi(glfw::ContextCreationApi::Native));
glfw.window_hint(glfw::WindowHint::ContextVersion(self.gl_version.0, self.gl_version.1));
glfw.window_hint(glfw::WindowHint::OpenGlProfile(glfw::OpenGlProfileHint::Core));
glfw.window_hint(glfw::WindowHint::OpenGlForwardCompat(true));
}
glfw.window_hint(glfw::WindowHint::Samples(Some(self.samples)));
glfw.window_hint(glfw::WindowHint::RedBits(Some(self.redbits)));
glfw.window_hint(glfw::WindowHint::GreenBits(Some(self.greenbits)));
glfw.window_hint(glfw::WindowHint::BlueBits(Some(self.bluebits)));
glfw.window_hint(glfw::WindowHint::AlphaBits(Some(self.alphabits)));
glfw.window_hint(glfw::WindowHint::DepthBits(Some(self.depthbits)));
glfw.window_hint(glfw::WindowHint::StencilBits(Some(self.stencilbits)));
glfw.window_hint(glfw::WindowHint::Stereo(false));
glfw.window_hint(glfw::WindowHint::DoubleBuffer(true));
let (mut window, events_receiver) = if self.fullscreen{
glfw.with_primary_monitor(|glfw: &mut glfw::Glfw, m: Option<&glfw::Monitor>| {
let monitor = m.unwrap();
let window_mode = glfw::WindowMode::FullScreen(monitor);
let (w, h) = self.size.unwrap_or_else(|| {
let mode = monitor.get_video_mode().unwrap();
(mode.width, mode.height)
});
match self.shared_context{
Some(window) => window.glfw_window.create_shared(w, h, &self.title, window_mode),
None => glfw.create_window(w, h, &self.title, window_mode)
}
})
}else{
let window_mode = glfw::WindowMode::Windowed;
let (w, h) = self.size.unwrap_or((1280, 720));
match self.shared_context{
Some(window) => window.glfw_window.create_shared(w, h, &self.title, window_mode),
None => glfw.create_window(w, h, &self.title, window_mode)
}
}.ok_or(util::Error::new("Failed to create GLFW window."))?;
window.set_sticky_keys(self.sticky_keys);
window.make_current();
window.set_all_polling(true);
glfw.set_swap_interval(self.swap_interval);
let (events_sender, events_stream) = SenderFromReceiver::new(events_receiver);
let events_stream = events_stream.map(|(_t,e)| e).rc();
let mouse_pos = events_stream.clone().filter_map(|e| {
if let glfw::WindowEvent::CursorPos(x,y) = e{
Some(Pnt2::new(x,y))
}else{
None
}
}).to_property(pnt2(0., 0.));
let window_data = WindowEventData::from(glfw, &window);
let events_stream = events_stream.clone().filter_map(move |e|{
Window::glfw_to_rin_event(mouse_pos.get(), &e, &window_data)
}).rc();
let esc_pressed = if self.esc_closes{
events_stream.clone()
.keys()
.released(Key::Escape)
.to_bool()
.to_property(false)
}else{
Property::new(false)
};
if let Some(position) = self.position {
window.set_pos(position.x, position.y);
if self.visible {
window.show();
}
}
let last_pos = window.get_pos();
let last_size = window.get_size();
let now = std::time::Instant::now();
let rin_window = Window{glfw: self.glfw.clone(),
glfw_window: window,
curr_fps:60.0f64,
last_pos,
last_size,
prev_time: now,
curr_frame_duration: Duration::default(),
prev_frame_time: now,
frames: 0,
total_frames: 0,
events_sender: events_sender,
update_sender: SenderRc::new(),
events_stream: events_stream,
esc_pressed,
swap_interval: self.swap_interval,
};
Ok(rin_window)
}
}
impl Drop for Window{
fn drop(&mut self){
self.glfw.window_gone()
}
}
impl Window{
pub fn new(w: u32, h: u32, title: &str) -> Result<Window>{
Builder::new(EventsPoll::new()?)
.size(w, h)
.title(title)
.build()
}
pub fn glfw_window_mut(&mut self) -> &mut glfw::Window{
&mut self.glfw_window
}
pub fn glfw_window(&self) -> &glfw::Window{
&self.glfw_window
}
pub fn set_adaptative_swap_interval(&mut self){
self.swap_interval = glfw::SwapInterval::Adaptive;
self.glfw.0.write().glfw.set_swap_interval(self.swap_interval);
}
pub fn window_mode(&self) -> WindowMode {
let ptr = unsafe { glfw::ffi::glfwGetWindowMonitor(self.glfw_window.window_ptr()) };
if ptr.is_null() {
WindowMode::Windowed
} else {
WindowMode::FullScreen(Monitor {
ptr,
glfw_guard: self.glfw.0.read()
})
}
}
pub fn set_monitor(&mut self, mode: WindowMode, xpos: i32, ypos: i32, width: u32, height: u32, refresh_rate: Option<u32>) {
let monitor_ptr = if let WindowMode::FullScreen(ref monitor) = mode {
monitor.ptr
} else {
std::ptr::null_mut()
};
unsafe {
glfw::ffi::glfwSetWindowMonitor(
self.glfw_window.window_ptr(),
monitor_ptr,
xpos as c_int,
ypos as c_int,
width as c_int,
height as c_int,
unwrap_dont_care(refresh_rate),
)
}
}
#[cfg(target_os="linux")]
fn keycode_to_codepoint(window_data: &WindowEventData, scancode: u32) -> char{
use window_platform::xlib::{XkbGetState, Display, XKeyEvent,KeyPress,NoSymbol,Xutf8LookupString, _XIC};
use window_platform::xlib::{XLookupChars, XLookupBoth, XLookupKeySym, XkbStatePtr, ControlMask};
use std::os::raw::c_uchar;
#[allow(non_upper_case_globals)]
const XkbUseCoreKbd: u32 = 0x0100;
#[allow(dead_code)]
struct XkbStateRec{
group: c_uchar,
locked_group: c_uchar,
base_group: c_uchar,
latched_group: c_uchar,
mods: c_uchar,
base_mods: c_uchar,
latched_mods: c_uchar,
locked_mods: c_uchar,
compat_state: c_uchar,
grab_mods: c_uchar,
compat_grab_mods: c_uchar,
lookup_mods: c_uchar,
compat_lookup_mods: c_uchar,
ptr_buttons: c_ushort,
}
unsafe{
let mut xkb_state: XkbStateRec = mem::MaybeUninit::uninit().assume_init() ;
XkbGetState(window_data.display as *mut Display, XkbUseCoreKbd, (&mut xkb_state) as *mut XkbStateRec as XkbStatePtr);
let mut ev: XKeyEvent = mem::zeroed();
ev.keycode = scancode;
ev.state = xkb_state.mods as u32 & !ControlMask;
ev.display = window_data.display as *mut Display;
ev.type_ = KeyPress;
let mut keysym = NoSymbol as u64;
let mut status = 0;
let mut buffer = [0u8;32];
let len = mem::size_of_val(&buffer) - 1;
let count = Xutf8LookupString(window_data.xic as *mut _XIC, &mut ev, buffer.as_mut_ptr() as *mut i8, len as i32, &mut keysym, &mut status);
if (count > 0 && (status == XLookupChars || status == XLookupBoth)) || status == XLookupKeySym {
const OFFSETS: [u32;6] =
[
0x00000000, 0x00003080, 0x000e2080,
0x03c82080, 0xfa082080, 0x82082080
];
let mut idx = 0;
let mut ch: u32 = 0;
let mut count = 0;
loop {
ch = (ch << 6) + buffer[idx] as u32;
idx+=1;
count+=1;
if (buffer[idx] & 0xc0) != 0x80 { break };
}
if count>6 {
return '\0';
}else{
return ::std::char::from_u32(ch as u32 - OFFSETS[count - 1]).unwrap();
}
}else{
return '\0';
}
}
}
#[cfg(target_os="macos")]
fn keycode_to_codepoint(window_data: &WindowEventData, scancode: u32) -> char{
scancode as u8 as char
}
#[cfg(target_os="windows")]
fn keycode_to_codepoint(_: &WindowEventData, scancode: u32) -> char{
use window_platform::um::winuser::*;
use std::os::windows::ffi::OsStringExt;
let mut buf = [0;3];
let mut keyboard_state = [0;256];
unsafe{
GetKeyboardState(keyboard_state.as_mut_ptr());
keyboard_state[VK_LCONTROL as usize] = 0;
keyboard_state[VK_RCONTROL as usize] = 0;
keyboard_state[VK_CONTROL as usize] = 0;
let virtual_key = MapVirtualKeyW(scancode, MAPVK_VSC_TO_VK_EX);
let ret = ToUnicode(virtual_key, scancode, keyboard_state.as_ptr(), buf.as_mut_ptr(), 2, 0);
if ret == 1 {
std::ffi::OsString::from_wide(&buf).to_str().unwrap().chars().next().unwrap()
}else{
'\0'
}
}
}
fn glfw_to_rin_key(key: glfw::Key, scancode: i32, window_data: &WindowEventData) ->Key{
match key{
glfw::Key::World1 => Key::World1,
glfw::Key::World2 => Key::World2,
glfw::Key::Escape => Key::Escape,
glfw::Key::Enter => Key::Enter,
glfw::Key::Tab => Key::Tab,
glfw::Key::Backspace => Key::Backspace,
glfw::Key::Insert => Key::Insert,
glfw::Key::Delete => Key::Delete,
glfw::Key::Right => Key::Right,
glfw::Key::Left => Key::Left,
glfw::Key::Down => Key::Down,
glfw::Key::Up => Key::Up,
glfw::Key::PageUp => Key::PageUp,
glfw::Key::PageDown => Key::PageDown,
glfw::Key::Home => Key::Home,
glfw::Key::End => Key::End,
glfw::Key::CapsLock => Key::CapsLock,
glfw::Key::ScrollLock => Key::ScrollLock,
glfw::Key::NumLock => Key::NumLock,
glfw::Key::PrintScreen => Key::PrintScreen,
glfw::Key::Pause => Key::Pause,
glfw::Key::F1 => Key::F1,
glfw::Key::F2 => Key::F2,
glfw::Key::F3 => Key::F3,
glfw::Key::F4 => Key::F4,
glfw::Key::F5 => Key::F5,
glfw::Key::F6 => Key::F6,
glfw::Key::F7 => Key::F7,
glfw::Key::F8 => Key::F8,
glfw::Key::F9 => Key::F9,
glfw::Key::F10 => Key::F10,
glfw::Key::F11 => Key::F11,
glfw::Key::F12 => Key::F12,
glfw::Key::F13 => Key::F13,
glfw::Key::F14 => Key::F14,
glfw::Key::F15 => Key::F15,
glfw::Key::F16 => Key::F16,
glfw::Key::F17 => Key::F17,
glfw::Key::F18 => Key::F18,
glfw::Key::F19 => Key::F19,
glfw::Key::F20 => Key::F20,
glfw::Key::F21 => Key::F21,
glfw::Key::F22 => Key::F22,
glfw::Key::F23 => Key::F23,
glfw::Key::F24 => Key::F24,
glfw::Key::F25 => Key::F25,
glfw::Key::Kp0 => Key::Kp0,
glfw::Key::Kp1 => Key::Kp1,
glfw::Key::Kp2 => Key::Kp2,
glfw::Key::Kp3 => Key::Kp3,
glfw::Key::Kp4 => Key::Kp4,
glfw::Key::Kp5 => Key::Kp5,
glfw::Key::Kp6 => Key::Kp6,
glfw::Key::Kp7 => Key::Kp7,
glfw::Key::Kp8 => Key::Kp8,
glfw::Key::Kp9 => Key::Kp9,
glfw::Key::KpDecimal => Key::KpDecimal,
glfw::Key::KpDivide => Key::KpDivide,
glfw::Key::KpMultiply => Key::KpMultiply,
glfw::Key::KpSubtract => Key::KpSubtract,
glfw::Key::KpAdd => Key::KpAdd,
glfw::Key::KpEnter => Key::KpEnter,
glfw::Key::KpEqual => Key::KpEqual,
glfw::Key::LeftShift => Key::LeftShift,
glfw::Key::LeftControl => Key::LeftControl,
glfw::Key::LeftAlt => Key::LeftAlt,
glfw::Key::LeftSuper => Key::LeftSuper,
glfw::Key::RightShift => Key::RightShift,
glfw::Key::RightControl => Key::RightControl,
glfw::Key::RightAlt => Key::RightAlt,
glfw::Key::RightSuper => Key::RightSuper,
glfw::Key::Menu => Key::Menu,
glfw::Key::Unknown => Key::Unknown,
_ => Key::Codepoint(Window::keycode_to_codepoint(window_data, scancode as u32)),
}
}
fn glfw_to_rin_mods(mods: glfw::Modifiers) -> KeyModifiers {
let mut rinmods = KeyModifiers::empty();
if mods.contains(glfw::Modifiers::Shift) {
rinmods |=KeyModifiers::SHIFT;
}
if mods.contains(glfw::Modifiers::Alt) {
rinmods |=KeyModifiers::ALT;
}
if mods.contains(glfw::Modifiers::Control) {
rinmods |=KeyModifiers::CONTROL;
}
if mods.contains(glfw::Modifiers::Super) {
rinmods |=KeyModifiers::SUPER;
}
rinmods
}
fn glfw_to_rin_event(last_mouse_pos: &Pnt2<f64>, event: &glfw::WindowEvent, window_data: &WindowEventData) -> Option<Event>{
match event {
&glfw::WindowEvent::Close => Some(Event::WindowClosing),
&glfw::WindowEvent::Pos(x, y) => Some(Event::WindowMoved{pos: pnt2(x,y)}),
&glfw::WindowEvent::Size(w, h) => Some(Event::WindowResized{size: vec2(w,h)}),
&glfw::WindowEvent::Refresh => None,
&glfw::WindowEvent::Focus(true) => Some(Event::FocusGained),
&glfw::WindowEvent::Focus(false) => Some(Event::FocusLost),
&glfw::WindowEvent::Iconify(true) => None,
&glfw::WindowEvent::Iconify(false) => None,
&glfw::WindowEvent::FramebufferSize(_w, _h) => None,
&glfw::WindowEvent::Char(character) => Some(Event::Char{character: character}),
&glfw::WindowEvent::MouseButton(button, action, mods) => {
match action{
glfw::Action::Press | glfw::Action::Repeat => {
let rin_button = glfw_to_rin_mouse_button(button);
Some(Event::MousePressed{
pos: *last_mouse_pos,
button: rin_button,
mods: Window::glfw_to_rin_mods(mods)
})
},
glfw::Action::Release => {
let rin_button = glfw_to_rin_mouse_button(button);
Some(Event::MouseReleased{
pos: *last_mouse_pos,
button: rin_button,
mods: Window::glfw_to_rin_mods(mods)
})
}
}
},
&glfw::WindowEvent::CursorPos(x,y) => {
Some(Event::MouseMoved{pos: Pnt2::new(x,y) })
},
&glfw::WindowEvent::CursorEnter(false) => None,
&glfw::WindowEvent::CursorEnter(true) => None,
&glfw::WindowEvent::Scroll(x, y)
=> Some(Event::Scroll{scroll: Vec2::new(x,y)}),
&glfw::WindowEvent::Key(key, scancode, action, mods) => {
let key = Window::glfw_to_rin_key(key, scancode, window_data);
let mods = unsafe{ mem::transmute(mods) };
let rin_event = match action{
glfw::Action::Press => {
Some(Event::KeyPressed{key, mods, repeat: false})
},
glfw::Action::Repeat => {
Some(Event::KeyPressed{key, mods, repeat: true})
}
glfw::Action::Release => {
Some(Event::KeyReleased{key: key})
}
};
rin_event
},
&glfw::WindowEvent::FileDrop(ref paths) =>{
Some(Event::Dropped{paths: paths.clone()})
},
&glfw::WindowEvent::CharModifiers(_,_) => None,
&glfw::WindowEvent::Maximize(_) => None,
&glfw::WindowEvent::ContentScale(_, _) => None,
}
}
}
impl WindowExt for Window{
fn make_current(&mut self){
self.glfw_window.make_current();
}
fn swap_buffers(&mut self){
self.glfw_window.swap_buffers();
}
fn update(&mut self){
self.frames += 1;
let now = Instant::now();
self.curr_frame_duration = now - self.prev_frame_time;
self.prev_frame_time = now;
if now - self.prev_time >= Duration::from_secs(1){
self.curr_fps = util::calc_fps(now, self.prev_time, self.frames);
self.prev_time = now;
self.frames = 0;
}
self.total_frames += 1;
let delta_s = self.curr_frame_duration_s();
self.update_sender.send(Event::Update{delta: delta_s});
self.events_sender.poll();
if *self.esc_pressed.get() {
self.glfw_window.set_should_close(true);
}
}
fn fps(&self) -> f64{
self.curr_fps
}
fn frames(&self) -> u64{
self.total_frames
}
fn event_stream<'a>(&mut self) -> Stream<'a, Event>{
self.events_stream.clone().merge(self.update_sender.stream())
}
fn set_swap_interval(&mut self, frames: u32){
if frames == 0 {
self.swap_interval = glfw::SwapInterval::None
}else{
self.swap_interval = glfw::SwapInterval::Sync(frames)
};
self.glfw.0.write().glfw.set_swap_interval(self.swap_interval);
}
fn curr_frame_duration(&self) -> Duration {
self.curr_frame_duration
}
fn time_elapsed_ns(&self) -> u64{
(self.glfw.0.read().glfw.get_time() * 1000000000.0) as u64
}
fn size(&self) -> Vec2<i32>{
let (x,y) = self.glfw_window.get_size();
vec2(x,y)
}
fn width(&self) -> i32{
self.size().x
}
fn height(&self) -> i32{
self.size().y
}
fn aspect_ratio(&self) -> f32{
self.size().x as f32 / self.size().y as f32
}
fn set_position(&mut self, pos: Pnt2<i32>){
self.glfw_window.set_pos(pos.x, pos.y);
}
fn position(&self) -> Pnt2<i32>{
let (x,y) = self.glfw_window.get_pos();
pnt2(x,y)
}
fn dpi(&self) -> u32{
self.glfw.0.write().glfw.with_primary_monitor(|_,primary_monitor| {
let (_w,h) = primary_monitor.unwrap().get_physical_size();
let height = primary_monitor.unwrap().get_video_mode().unwrap().height;
let h_inches = h as f32/25.4 as f32;
(height as f32 / h_inches) as u32
})
}
fn resolution_factor(&self) -> f32{
1.0
}
fn screen_size(&self) -> Vec2<u32>{
self.glfw.0.write().glfw.with_primary_monitor(|_,primary_monitor| {
let video_mode = primary_monitor.unwrap().get_video_mode().unwrap();
vec2(video_mode.width,video_mode.height)
})
}
fn should_close(&self) -> bool{
self.glfw_window.should_close()
}
fn set_should_close(&mut self){
self.glfw_window.set_should_close(true)
}
fn set_fullscreen(&mut self, fullscreen: bool){
if fullscreen {
self.last_pos = self.glfw_window.get_pos();
self.last_size = self.glfw_window.get_size();
let mut glfw = self.glfw.0.write();
let glfw_window = &mut self.glfw_window;
glfw.glfw.with_primary_monitor_mut(|_: &mut _, m: Option<&glfw::Monitor>| {
let monitor = m.unwrap();
let mode = monitor.get_video_mode().unwrap();
glfw_window.set_monitor(glfw::WindowMode::FullScreen(&monitor),
0, 0,
mode.width, mode.height,
Some(mode.refresh_rate));
});
} else {
self.glfw_window.set_monitor(glfw::WindowMode::Windowed,
self.last_pos.0, self.last_pos.1,
self.last_size.0 as u32, self.last_size.1 as u32,
None);
}
self.glfw.0.write().glfw.set_swap_interval(self.swap_interval);
}
fn set_cursor(&mut self, cursor: Cursor){
self.glfw_window.set_cursor(Some(into_glfw_cursor(cursor)));
}
fn set_cursor_mode(&mut self, cursor_mode: CursorMode){
self.glfw_window.set_cursor_mode(match cursor_mode {
CursorMode::Disabled => glfw::CursorMode::Disabled,
CursorMode::Enabled => glfw::CursorMode::Normal,
CursorMode::Hidden => glfw::CursorMode::Hidden,
})
}
}
fn into_glfw_cursor(cursor: Cursor) -> glfw::Cursor{
match cursor{
Cursor::Arrow => glfw::Cursor::standard(glfw::StandardCursor::Arrow),
Cursor::IBeam => glfw::Cursor::standard(glfw::StandardCursor::IBeam),
Cursor::Crosshair => glfw::Cursor::standard(glfw::StandardCursor::Crosshair),
Cursor::Hand => glfw::Cursor::standard(glfw::StandardCursor::Hand),
Cursor::HResize => glfw::Cursor::standard(glfw::StandardCursor::HResize),
Cursor::VResize => glfw::Cursor::standard(glfw::StandardCursor::VResize),
}
}
fn glfw_to_rin_mouse_button(button: glfw::MouseButton) -> MouseButton{
match button{
glfw::MouseButton::Button1 => {MouseButton::Left},
glfw::MouseButton::Button2 => {MouseButton::Right},
glfw::MouseButton::Button3 => {MouseButton::Middle},
glfw::MouseButton::Button4 => {MouseButton::Button4},
glfw::MouseButton::Button5 => {MouseButton::Button5},
glfw::MouseButton::Button6 => {MouseButton::Button6},
glfw::MouseButton::Button7 => {MouseButton::Button7},
glfw::MouseButton::Button8 => {MouseButton::Button8},
}
}
#[cfg(any(feature="gl", feature="gles"))]
impl glin::GlWindow for Window{
fn proc_address(&mut self, procname: &str) -> *const c_void{
self.glfw_window.get_proc_address(procname) as *const c_void
}
}
thread_local!(static GLFW_CLIPBOARD: RefCell<glfw::Window> = {
let glfw = EventsPoll::new().unwrap();
let glfw = &mut glfw.0.write().glfw;
glfw.window_hint(glfw::WindowHint::Visible(false));
let (window, _events_receiver) = glfw.create_window(10,10,"rin clipboard", glfw::WindowMode::Windowed)
.unwrap();
RefCell::new(window)
});
pub fn set_clipboard_string(string: &str){
GLFW_CLIPBOARD.with(|window| window.borrow_mut().set_clipboard_string(string))
}
pub fn clipboard_string() -> Option<String>{
GLFW_CLIPBOARD.with(|window| window.borrow().get_clipboard_string())
}