use crate::graphics::{
Graphics,
GraphicsSettings,
two_dimensions::Graphics2D,
};
#[cfg(feature="3D")]
use crate::graphics::three_dimensions::Graphics3D;
#[cfg(feature="fps_counter")]
use super::fps;
use super::{
window_width,
window_height,
window_center,
InnerWindowEvent,
GeneralSettings,
};
use glium::{
Display,
Surface,
Version,
draw_parameters::{
DrawParameters,
Blend,
BlendingFunction,
LinearBlendingFactor,
BackfaceCullingMode,
},
texture::RawImage2d,
backend::glutin::DisplayCreationError,
SwapBuffersError,
};
use glium::glutin::{
ContextBuilder,
NotCurrent,
event_loop::{EventLoop,EventLoopClosed,EventLoopProxy},
window::WindowBuilder,
};
use image::{
ImageFormat,
ImageBuffer,
DynamicImage
};
use std::{
path::Path,
time::{Instant,Duration}
};
pub struct WindowBase{
pub display:Display,
pub graphics2d:Graphics2D,
#[cfg(feature="3D")]
pub graphics3d:Graphics3D,
pub event_loop:EventLoop<InnerWindowEvent>,
pub event_loop_proxy:EventLoopProxy<InnerWindowEvent>,
#[cfg(not(feature="lazy"))]
pub update_interval:Duration,
#[cfg(not(feature="lazy"))]
pub next_update:Instant,
#[cfg(feature="fps_counter")]
pub frames_passed:u32,
#[cfg(feature="fps_counter")]
pub time:Instant,
}
impl WindowBase{
pub fn raw(
window_builder:WindowBuilder,
context_builder:ContextBuilder<NotCurrent>,
graphics_settings:GraphicsSettings,
event_loop:EventLoop<InnerWindowEvent>,
general_settings:GeneralSettings,
)->Result<WindowBase,DisplayCreationError>{
let display=Display::new(window_builder,context_builder,&event_loop)?;
let size=display.gl_window().window().inner_size();
unsafe{
window_width=size.width as f32;
window_height=size.height as f32;
window_center=[window_width/2f32,window_height/2f32];
}
let Version(..,m,l)=display.get_supported_glsl_version();
let glsl=match m{
1 if l<3 =>{
120
}
_=>{
140
}
};
if let Some([r,g,b,a])=general_settings.initial_colour{
let mut frame=display.draw();
frame.clear_color(r,g,b,a);
frame.finish().unwrap();
}
let graphics2d=Graphics2D::new(&display,graphics_settings,glsl);
#[cfg(feature="3D")]
let graphics3d=Graphics3D::new();
let proxy=event_loop.create_proxy();
Ok(Self{
graphics2d,
#[cfg(feature="3D")]
graphics3d,
display,
event_loop,
event_loop_proxy:proxy,
#[cfg(not(feature="lazy"))]
update_interval:Duration::from_secs(1).checked_div(general_settings.updates_per_second).expect("UPD = 0"),
#[cfg(not(feature="lazy"))]
next_update:Instant::now(),
#[cfg(feature="fps_counter")]
frames_passed:0u32,
#[cfg(feature="fps_counter")]
time:Instant::now(),
})
}
#[inline(always)]
pub fn request_event_loop_close(&self)->Result<(),EventLoopClosed<InnerWindowEvent>>{
self.event_loop_proxy.send_event(InnerWindowEvent::EventLoopCloseRequested)
}
}
impl WindowBase{
pub fn draw<F:FnOnce(&mut DrawParameters,&mut Graphics)>(&mut self,f:F)->Result<(),SwapBuffersError>{
let mut draw_parameters=default_draw_parameters();
let mut frame=self.display.draw();
let mut g=Graphics::new(
&mut self.graphics2d,
#[cfg(feature="3D")]&mut self.graphics3d,
&mut frame
);
f(&mut draw_parameters,&mut g);
frame.finish()
}
}
impl WindowBase{
pub fn screenshot(&self)->Option<DynamicImage>{
let image:RawImage2d<u8>=match self.display.read_front_buffer(){
Ok(t)=>t,
Err(_)=>return Option::None
};
let image=match ImageBuffer::from_raw(image.width,image.height,image.data.into_owned()){
Option::Some(i)=>i,
Option::None=>return Option::None
};
Some(DynamicImage::ImageRgba8(image).flipv())
}
pub fn save_screenshot<P:AsRef<Path>>(&self,path:P){
let image:RawImage2d<u8>=match self.display.read_front_buffer(){
Ok(t)=>t,
Err(_)=>return
};
let image=match ImageBuffer::from_raw(image.width,image.height,image.data.into_owned()){
Option::Some(i)=>i,
Option::None=>return
};
let image=DynamicImage::ImageRgba8(image).flipv();
if let Err(_)=image.save_with_format(path,ImageFormat::Png){
return
}
}
}
impl WindowBase{
#[cfg(feature="fps_counter")]
pub (crate) fn count_fps(&mut self){
self.frames_passed+=1;
let current_time=Instant::now();
let time_passed=current_time.duration_since(self.time);
if Duration::from_secs(1)<time_passed{
unsafe{
fps=self.frames_passed;
}
self.frames_passed=0;
self.time=current_time;
}
}
#[cfg(not(feature="lazy"))]
pub (crate) fn update_check(&mut self){
let now=Instant::now();
if self.next_update<now{
self.event_loop_proxy
.send_event(InnerWindowEvent::Update)
.expect("Dead event loop");
self.next_update+=self.update_interval;
}
}
}
fn default_draw_parameters<'a>()->DrawParameters<'a>{
DrawParameters{
blend:Blend{
color:BlendingFunction::Addition{
source:LinearBlendingFactor::SourceAlpha,
destination:LinearBlendingFactor::OneMinusSourceAlpha,
},
alpha:BlendingFunction::Addition{
source:LinearBlendingFactor::One,
destination:LinearBlendingFactor::One,
},
constant_value:(1f32,1f32,1f32,1f32),
},
backface_culling:BackfaceCullingMode::CullingDisabled,
..DrawParameters::default()
}
}