use std;
use std::sync::atomic;
use glium;
use glutin;
use image;
use log;
use rs_utils;
use vec_map::VecMap;
pub mod params;
pub mod resource;
pub mod viewport;
pub use self::resource::Resource;
pub use self::viewport::Viewport;
const INITIAL_VIEWPORT_VECMAP_CAPACITY : usize = 4;
const MAX_SCREENSHOT_WORKER_COUNT : u8 = 8;
static SCREENSHOT_WORKER_COUNT : atomic::AtomicU8 = atomic::AtomicU8::new (0);
pub struct Render <R : Resource = resource::Default> {
pub glium_display : glium::Display <glutin::surface::WindowSurface>,
pub window : winit::window::Window,
pub resource : R,
pub frame_fun : fn (&mut Render <R>, Option <&mut glium::Frame>),
pub clear_color : [f32; 4],
pub clear_depth : f32,
pub clear_stencil : i32,
viewports : VecMap <Viewport>
}
pub fn frame_fun_default <R : Resource> (
render : &mut Render <R>, frame : Option <&mut glium::Frame>
) {
use glium::Surface;
log::trace!("frame fun default...");
let mut maybe_frame : Option <glium::Frame> = None;
let glium_frame = match frame {
Some (frame) => frame,
None => {
maybe_frame = Some (render.glium_display.draw());
maybe_frame.as_mut().unwrap()
}
};
glium_frame.clear_all (
render.clear_color_tuple(), render.clear_depth, render.clear_stencil);
Resource::draw_3d (render, glium_frame);
Resource::draw_2d (render, glium_frame);
if let Some (glium_frame) = maybe_frame.take() {
glium_frame.finish().unwrap();
}
log::trace!("...frame fun default");
}
pub fn frame_fun_default_2d <R : Resource> (
render : &mut Render <R>, frame : Option <&mut glium::Frame>
) {
use glium::Surface;
log::trace!("frame fun default 2d...");
let mut maybe_frame = None;
let glium_frame = match frame {
Some (frame) => frame,
None => {
maybe_frame = Some (render.glium_display.draw());
maybe_frame.as_mut().unwrap()
}
};
glium_frame.clear_all (
render.clear_color_tuple(), render.clear_depth, render.clear_stencil);
Resource::draw_2d (render, glium_frame);
if let Some (glium_frame) = maybe_frame.take() {
glium_frame.finish().unwrap();
}
log::trace!("...frame fun default 2d");
}
pub fn frame_fun_default_3d <R : Resource> (
render : &mut Render <R>, frame : Option <&mut glium::Frame>
) {
use glium::Surface;
log::trace!("frame fun default 3d...");
let mut maybe_frame = None;
let glium_frame = match frame {
Some (frame) => frame,
None => {
maybe_frame = Some (render.glium_display.draw());
maybe_frame.as_mut().unwrap()
}
};
glium_frame.clear_all (
render.clear_color_tuple(), render.clear_depth, render.clear_stencil);
Resource::draw_3d (render, glium_frame);
if let Some (glium_frame) = maybe_frame.take() {
glium_frame.finish().unwrap();
}
log::trace!("...frame fun default 3d");
}
impl <R : Resource> Render <R> {
pub fn new (
glium_display : glium::Display <glutin::surface::WindowSurface>,
window : winit::window::Window
) -> Self {
let resource = R::new (&glium_display);
let frame_fun = frame_fun_default::<R>;
let clear_color = Default::default();
let clear_depth = Default::default();
let clear_stencil = Default::default();
let viewports = Default::default();
let mut render = Render {
glium_display, window, frame_fun, clear_color, clear_depth, clear_stencil,
viewports, resource
};
render.initialize();
render
}
#[inline]
pub const fn clear_color_tuple(&self) -> (f32, f32, f32, f32) {
let [r, g, b, a] = self.clear_color;
(r, g, b, a)
}
pub const fn viewports (&self) -> &VecMap <Viewport> {
&self.viewports
}
pub const fn viewports_mut (&mut self) -> &mut VecMap <Viewport> {
&mut self.viewports
}
pub fn get_viewport (&self, key : usize) -> Option <&Viewport> {
self.viewports.get (key)
}
pub fn get_viewport_mut (&mut self, key : usize) -> Option <&mut Viewport> {
self.viewports.get_mut (key)
}
pub fn reset (&mut self) {
Resource::reset (self);
self.initialize();
}
#[inline]
pub fn do_frame (&mut self, frame : Option <&mut glium::Frame>) {
(self.frame_fun) (self, frame)
}
pub fn screenshot (&self) {
let raw : glium::texture::RawImage2d <u8> =
self.glium_display.read_front_buffer().unwrap();
let worker_count = SCREENSHOT_WORKER_COUNT
.fetch_add (1, atomic::Ordering::SeqCst);
if worker_count < MAX_SCREENSHOT_WORKER_COUNT {
let _ = std::thread::spawn (move || {
let mut image_buffer = image::ImageBuffer::from_raw (
raw.width, raw.height, raw.data.into_owned()).unwrap();
image_buffer = image::imageops::flip_vertical (&image_buffer);
let image = image::DynamicImage::ImageRgba8 (image_buffer);
let filepath = rs_utils::file::file_path_incremental_with_extension (
std::path::Path::new ("screenshot.png")
).unwrap();
println!("saving {}...", filepath.display());
image.save (filepath).unwrap();
SCREENSHOT_WORKER_COUNT.fetch_sub (1, atomic::Ordering::SeqCst);
});
}
}
pub fn report_sizes() {
use std::mem::size_of;
use rs_utils::show;
use crate::{vertex, Camera2d, Camera3d};
println!("Render report sizes...");
show!(size_of::<Self>());
show!(size_of::<R>());
show!(size_of::<glium::VertexBuffer <vertex::Vert2d>>());
show!(size_of::<glium::IndexBuffer <u8>>());
show!(size_of::<glium::texture::Texture2d>());
show!(size_of::<glium::texture::Texture2dArray>());
show!(size_of::<Viewport>());
show!(size_of::<Camera2d>());
show!(size_of::<Camera3d>());
vertex::report_sizes();
println!("...Render report sizes");
}
fn initialize (&mut self) {
self.frame_fun = frame_fun_default::<R>;
self.clear_color = [0.0, 0.0, 1.0, 1.0]; self.clear_depth = 1.0;
self.clear_stencil = 0;
let (resolution_width, resolution_height) = self.window.inner_size().into();
log::debug!(resolution:?=(resolution_width, resolution_height);
"create viewport");
self.viewports = {
let mut v = VecMap::with_capacity (INITIAL_VIEWPORT_VECMAP_CAPACITY);
assert!{
v.insert (0, Viewport::new (glium::Rect {
left: 0, bottom: 0, width: resolution_width, height: resolution_height
})).is_none()
}
v
};
R::init (self)
}
}
impl <R : Resource> Drop for Render <R> {
fn drop (&mut self) {
while 0 < SCREENSHOT_WORKER_COUNT.load (atomic::Ordering::SeqCst) {
std::thread::sleep (std::time::Duration::from_millis (100));
}
}
}
impl <R : Resource> std::fmt::Debug for Render <R> {
fn fmt (&self, f : &mut std::fmt::Formatter) -> Result <(), std::fmt::Error> {
if f.alternate() {
write!(f, "Render {{
glium_display: {:?},
resource: {:p},
frame_fun: {:p},
clear_color: {:?},
clear_depth: {},
clear_stencil: {},
viewports: {:?}
}}",
self.glium_display, &self.resource, &self.frame_fun, self.clear_color,
self.clear_depth, self.clear_stencil,
self.viewports.keys().collect::<Vec<_>>()
)
} else {
write!(f, "Render {{ glium_display: {:?}, resource: {:p}, frame_fun: {:p}, \
clear_color: {:?}, clear_depth: {}, clear_stencil: {}, viewports: {:?} }}",
self.glium_display, &self.resource, &self.frame_fun, self.clear_color,
self.clear_depth, self.clear_stencil,
self.viewports.keys().collect::<Vec<_>>()
)
}
}
}