pixelpwnr_render/renderer/
mod.rs1mod ref_values;
2pub mod stats_renderer;
3
4use std::sync::atomic::{AtomicBool, Ordering};
5use std::sync::Arc;
6use std::time::{Duration, Instant};
7
8use gfx::handle::ShaderResourceView;
9use gfx::texture::{AaMode, Kind, Mipmap};
10use gfx::traits::FactoryExt;
11use gfx_glutin::{ContextBuilderExt, WindowInitExt, WindowUpdateExt};
12use glutin::dpi::LogicalSize;
13use glutin::event::{Event, VirtualKeyCode, WindowEvent};
14use glutin::{ContextBuilder, GlProfile, GlRequest, Robustness};
15
16use gfx::{self, *};
17use glutin::event_loop::{ControlFlow, EventLoop};
18use glutin::window::{Fullscreen, WindowBuilder};
19use old_school_gfx_glutin_ext as gfx_glutin;
20
21use crate::fps_counter::FpsCounter;
22use crate::pixmap::Pixmap;
23use crate::primitive::create_quad_max;
24use crate::vertex::Vertex;
25use stats_renderer::{Corner, StatsRenderer};
26
27pub(crate) type ColorFormat = gfx::format::Rgba8;
29pub(crate) type DepthFormat = gfx::format::DepthStencil;
30type F = gfx_device_gl::Factory;
31pub(crate) type R = gfx_device_gl::Resources;
32
33const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
35
36gfx_defines! {
38 pipeline pipe {
39 vbuf: gfx::VertexBuffer<Vertex> = (),
40 image: gfx::TextureSampler<[f32; 4]> = "t_Image",
41 out: gfx::RenderTarget<ColorFormat> = "Target0",
42 }
43}
44
45pub struct Renderer<'a> {
47 title: &'a str,
49
50 pixmap: Arc<Pixmap>,
52
53 stats: StatsRenderer<F>,
55
56 events_loop: EventLoop<()>,
58
59 #[allow(unused)]
61 fps: FpsCounter,
62}
63
64impl<'a> Renderer<'a> {
65 pub fn new(title: &'a str, pixmap: Arc<Pixmap>) -> Renderer<'a> {
70 Renderer {
72 title,
73 pixmap,
74 stats: StatsRenderer::new(Corner::TopLeft),
75 events_loop: EventLoop::new(),
76 fps: FpsCounter::new(),
77 }
78 }
79
80 pub fn run(
81 mut self,
82 fullscreen: bool,
83 stats_size: u8,
84 stats_offset: (u32, u32),
85 stats_padding: i32,
86 stats_col_spacing: i32,
87 keep_running: Arc<AtomicBool>,
88 ) {
89 let size = self.pixmap.dimensions();
91
92 let monitor = if fullscreen {
95 Some(Fullscreen::Borderless(self.events_loop.primary_monitor()))
96 } else {
97 None
98 };
99
100 let builder = WindowBuilder::new()
102 .with_title(self.title.to_string())
103 .with_fullscreen(monitor)
104 .with_inner_size(LogicalSize {
105 width: size.0 as f64,
106 height: size.1 as f64,
107 });
108
109 let (window, mut device, mut factory, mut main_color, mut main_depth) =
112 ContextBuilder::new()
113 .with_srgb(true)
114 .with_gl(GlRequest::Latest)
115 .with_gl_robustness(Robustness::TryRobustNoResetNotification)
116 .with_gl_profile(GlProfile::Core)
117 .with_multisampling(1)
118 .with_gfx_color_depth::<ColorFormat, DepthFormat>()
119 .with_vsync(true)
120 .build_windowed(builder, &self.events_loop)
121 .unwrap()
122 .init_gfx();
123
124 let my_window_id = window.window().id();
125
126 let mut encoder: gfx::Encoder<_, _> = factory.create_command_buffer().into();
133
134 let pso = factory
136 .create_pipeline_simple(
137 include_bytes!("../../shaders/screen.glslv"),
138 include_bytes!("../../shaders/screen.glslf"),
139 pipe::new(),
140 )
141 .unwrap();
142
143 let plane = create_quad_max();
145 let (vertex_buffer, slice) = plane.create_vertex_buffer(&mut factory);
146
147 let texture_kind = Kind::D2(size.0 as u16, size.1 as u16, AaMode::Single);
149
150 let base_image = (
152 Renderer::create_texture(&mut factory, self.pixmap.as_bytes(), texture_kind),
153 factory.create_sampler_linear(),
154 );
155
156 let mut data_depth = main_depth.clone();
158 let mut data = pipe::Data {
159 vbuf: vertex_buffer,
160 image: base_image,
161 out: main_color.clone(),
162 };
163
164 let dimensions = (size.0 as f32, size.1 as f32);
165 self.stats
167 .init(
168 factory.clone(),
169 dimensions,
170 main_color.clone(),
171 main_depth.clone(),
172 stats_size,
173 stats_offset,
174 stats_padding,
175 stats_col_spacing,
176 )
177 .expect("failed to initialize stats text renderer");
178
179 let mut next_frame_time = Instant::now();
180
181 self.events_loop.run(move |event, _target, control_flow| {
182 if !keep_running.load(Ordering::SeqCst) {
183 *control_flow = ControlFlow::Exit;
184 return;
185 }
186
187 let keycode = if let Event::WindowEvent { window_id, event } = &event {
188 if window_id == &my_window_id {
189 if let WindowEvent::KeyboardInput { input, .. } = event {
190 input.virtual_keycode
191 } else {
192 None
193 }
194 } else {
195 None
196 }
197 } else {
198 None
199 };
200
201 let is_close_request = if let Event::WindowEvent {
202 window_id,
203 event: WindowEvent::CloseRequested,
204 } = &event
205 {
206 window_id == &my_window_id
207 } else {
208 false
209 };
210
211 let exit = keycode == Some(VirtualKeyCode::Escape) || is_close_request;
212
213 if let Event::WindowEvent {
214 event: WindowEvent::Resized(s),
215 ..
216 } = event
217 {
218 let dimensions = (s.width as f32, s.height as f32);
219 window.update_gfx(&mut main_color, &mut main_depth);
221
222 window.update_gfx(&mut data.out, &mut data_depth);
224
225 self.stats.update_views(&window, dimensions);
227 }
228
229 if Instant::now() > next_frame_time || event == Event::MainEventsCleared {
232 data.image = (
233 Renderer::create_texture(&mut factory, self.pixmap.as_bytes(), texture_kind),
234 factory.create_sampler_linear(),
235 );
236
237 encoder.clear(&data.out, BLACK);
239
240 encoder.draw(&slice, &pso, &data);
242
243 self.stats.draw(&mut encoder, &main_color).unwrap();
245
246 encoder.flush(&mut device);
247
248 window.swap_buffers().unwrap();
250
251 device.cleanup();
252 next_frame_time = Instant::now() + Duration::from_millis(1);
254 }
255
256 if exit || !keep_running.load(Ordering::SeqCst) {
257 keep_running.store(false, Ordering::SeqCst);
258 } else {
259 *control_flow = ControlFlow::WaitUntil(next_frame_time);
260 }
261 });
262 }
263
264 pub fn run_default(self) {
266 self.run(false, 20, (10, 10), 12, 20, Arc::new(AtomicBool::new(true)));
267 }
268
269 pub fn stats(&self) -> &StatsRenderer<F> {
270 &self.stats
271 }
272
273 fn create_texture(factory: &mut F, data: &[u8], kind: Kind) -> ShaderResourceView<R, [f32; 4]> {
275 let (_, view) = factory
278 .create_texture_immutable_u8::<ColorFormat>(kind, Mipmap::Provided, &[data])
279 .unwrap();
280
281 view
282 }
283}