1use std;
7use std::sync::atomic;
8use glium;
9use glutin;
10use image;
11use log;
12use rs_utils;
13use vec_map::VecMap;
14
15pub mod params;
16pub mod resource;
17pub mod viewport;
18
19pub use self::resource::Resource;
20pub use self::viewport::Viewport;
21
22const INITIAL_VIEWPORT_VECMAP_CAPACITY : usize = 4;
24const MAX_SCREENSHOT_WORKER_COUNT : u8 = 8;
27static SCREENSHOT_WORKER_COUNT : atomic::AtomicU8 = atomic::AtomicU8::new (0);
34
35pub struct Render <R : Resource = resource::Default> {
52 pub glium_display : glium::Display <glutin::surface::WindowSurface>,
55 pub window : winit::window::Window,
56 pub resource : R,
58 pub frame_fun : fn (&mut Render <R>, Option <&mut glium::Frame>),
59 pub clear_color : [f32; 4],
60 pub clear_depth : f32,
61 pub clear_stencil : i32,
62 viewports : VecMap <Viewport>
63}
64
65pub fn frame_fun_default <R : Resource> (
68 render : &mut Render <R>, frame : Option <&mut glium::Frame>
69) {
70 use glium::Surface;
71 log::trace!("frame fun default...");
72 let mut maybe_frame : Option <glium::Frame> = None;
73 let glium_frame = match frame {
74 Some (frame) => frame,
75 None => {
76 maybe_frame = Some (render.glium_display.draw());
77 maybe_frame.as_mut().unwrap()
78 }
79 };
80 glium_frame.clear_all (
81 render.clear_color_tuple(), render.clear_depth, render.clear_stencil);
82 Resource::draw_3d (render, glium_frame);
83 Resource::draw_2d (render, glium_frame);
84 if let Some (glium_frame) = maybe_frame.take() {
85 glium_frame.finish().unwrap();
86 }
87 log::trace!("...frame fun default");
88}
89
90pub fn frame_fun_default_2d <R : Resource> (
92 render : &mut Render <R>, frame : Option <&mut glium::Frame>
93) {
94 use glium::Surface;
95 log::trace!("frame fun default 2d...");
96 let mut maybe_frame = None;
97 let glium_frame = match frame {
98 Some (frame) => frame,
99 None => {
100 maybe_frame = Some (render.glium_display.draw());
101 maybe_frame.as_mut().unwrap()
102 }
103 };
104 glium_frame.clear_all (
105 render.clear_color_tuple(), render.clear_depth, render.clear_stencil);
106 Resource::draw_2d (render, glium_frame);
107 if let Some (glium_frame) = maybe_frame.take() {
108 glium_frame.finish().unwrap();
109 }
110 log::trace!("...frame fun default 2d");
111}
112
113pub fn frame_fun_default_3d <R : Resource> (
115 render : &mut Render <R>, frame : Option <&mut glium::Frame>
116) {
117 use glium::Surface;
118 log::trace!("frame fun default 3d...");
119 let mut maybe_frame = None;
120 let glium_frame = match frame {
121 Some (frame) => frame,
122 None => {
123 maybe_frame = Some (render.glium_display.draw());
124 maybe_frame.as_mut().unwrap()
125 }
126 };
127 glium_frame.clear_all (
128 render.clear_color_tuple(), render.clear_depth, render.clear_stencil);
129 Resource::draw_3d (render, glium_frame);
130 if let Some (glium_frame) = maybe_frame.take() {
131 glium_frame.finish().unwrap();
132 }
133 log::trace!("...frame fun default 3d");
134}
135
136impl <R : Resource> Render <R> {
137 pub fn new (
139 glium_display : glium::Display <glutin::surface::WindowSurface>,
140 window : winit::window::Window
141 ) -> Self {
142 let resource = R::new (&glium_display);
143 let frame_fun = frame_fun_default::<R>;
144 let clear_color = Default::default();
145 let clear_depth = Default::default();
146 let clear_stencil = Default::default();
147 let viewports = Default::default();
148 let mut render = Render {
149 glium_display, window, frame_fun, clear_color, clear_depth, clear_stencil,
150 viewports, resource
151 };
152 render.initialize();
153 render
154 }
155
156 #[inline]
159 pub fn clear_color_tuple(&self) -> (f32, f32, f32, f32) {
160 let [r, g, b, a] = self.clear_color;
161 (r, g, b, a)
162 }
163
164 pub fn viewports (&self) -> &VecMap <Viewport> {
165 &self.viewports
166 }
167
168 pub fn viewports_mut (&mut self) -> &mut VecMap <Viewport> {
169 &mut self.viewports
170 }
171
172 pub fn get_viewport (&self, key : usize) -> Option <&Viewport> {
173 self.viewports.get (key)
174 }
175
176 pub fn get_viewport_mut (&mut self, key : usize) -> Option <&mut Viewport> {
177 self.viewports.get_mut (key)
178 }
179
180 pub fn reset (&mut self) {
185 Resource::reset (self);
186 self.initialize();
187 }
188
189 #[inline]
191 pub fn do_frame (&mut self, frame : Option <&mut glium::Frame>) {
192 (self.frame_fun) (self, frame)
193 }
194
195 pub fn screenshot (&self) {
201 let raw : glium::texture::RawImage2d <u8> =
202 self.glium_display.read_front_buffer().unwrap();
203 let worker_count = SCREENSHOT_WORKER_COUNT
204 .fetch_add (1, atomic::Ordering::SeqCst);
205 if worker_count < MAX_SCREENSHOT_WORKER_COUNT {
206 let _ = std::thread::spawn (move || {
207 let mut image_buffer = image::ImageBuffer::from_raw (
208 raw.width, raw.height, raw.data.into_owned()).unwrap();
209 image_buffer = image::imageops::flip_vertical (&image_buffer);
210 let image = image::DynamicImage::ImageRgba8 (image_buffer);
211 let filepath = rs_utils::file::file_path_incremental_with_extension (
213 std::path::Path::new ("screenshot.png")
214 ).unwrap();
215 println!("saving {filepath:?}...");
216 image.save (filepath).unwrap();
217 SCREENSHOT_WORKER_COUNT.fetch_sub (1, atomic::Ordering::SeqCst);
218 });
219 }
220 }
221
222 pub fn report_sizes() {
223 use std::mem::size_of;
224 use rs_utils::show;
225 use crate::{vertex, Camera2d, Camera3d};
226 println!("Render report sizes...");
227 show!(size_of::<Self>());
228 show!(size_of::<R>());
229 show!(size_of::<glium::VertexBuffer <vertex::Vert2d>>());
230 show!(size_of::<glium::IndexBuffer <u8>>());
231 show!(size_of::<glium::texture::Texture2d>());
232 show!(size_of::<glium::texture::Texture2dArray>());
233 show!(size_of::<Viewport>());
234 show!(size_of::<Camera2d>());
235 show!(size_of::<Camera3d>());
236 vertex::report_sizes();
237 println!("...Render report sizes");
238 }
239
240 fn initialize (&mut self) {
247 self.frame_fun = frame_fun_default::<R>;
248 self.clear_color = [0.0, 0.0, 1.0, 1.0]; self.clear_depth = 1.0;
250 self.clear_stencil = 0;
251 let (resolution_width, resolution_height) = self.window.inner_size().into();
252 log::debug!(resolution:?=(resolution_width, resolution_height);
253 "create viewport");
254 self.viewports = {
255 let mut v = VecMap::with_capacity (INITIAL_VIEWPORT_VECMAP_CAPACITY);
256 assert!{
257 v.insert (0, Viewport::new (glium::Rect {
258 left: 0, bottom: 0, width: resolution_width, height: resolution_height
259 })).is_none()
260 }
261 v
262 };
263 R::init (self)
264 }
265}
266
267impl <R : Resource> Drop for Render <R> {
268 fn drop (&mut self) {
269 while 0 < SCREENSHOT_WORKER_COUNT.load (atomic::Ordering::SeqCst) {
271 std::thread::sleep (std::time::Duration::from_millis (100));
272 }
273 }
274}
275
276impl <R : Resource> std::fmt::Debug for Render <R> {
277 fn fmt (&self, f : &mut std::fmt::Formatter) -> Result <(), std::fmt::Error> {
278 if f.alternate() {
279 write!(f, r#"Render {{
280 glium_display: {:?},
281 resource: {:p},
282 frame_fun: {:p},
283 clear_color: {:?},
284 clear_depth: {},
285 clear_stencil: {},
286 viewports: {:?}
287}}"#,
288 self.glium_display, &self.resource, &self.frame_fun, self.clear_color,
289 self.clear_depth, self.clear_stencil,
290 self.viewports.keys().collect::<Vec<_>>()
291 )
292 } else {
293 write!(f, "Render {{ glium_display: {:?}, resource: {:p}, frame_fun: {:p}, \
294 clear_color: {:?}, clear_depth: {}, clear_stencil: {}, viewports: {:?} }}",
295 self.glium_display, &self.resource, &self.frame_fun, self.clear_color,
296 self.clear_depth, self.clear_stencil,
297 self.viewports.keys().collect::<Vec<_>>()
298 )
299 }
300 }
301}