#[non_exhaustive]pub struct Framebuffer {
pub buffer_size: LogicalSize<i32>,
pub vp_size: PhysicalSize<i32>,
pub did_draw: bool,
pub inverted_y: bool,
pub internal: FramebufferInternal,
}
Expand description
The Framebuffer struct manages the framebuffer of a MGlFb window. Through this struct, you can
update the size and content of the buffer. Framebuffers are usually obtained through
MiniGlFb::glutin_breakout
, but they’re also returned by
init_framebuffer
.
§Basic usage
Firstly, one of the most important things to do when managing a Framebuffer manually is to make
sure that whenever the window is resized, the Framebuffer is the first to know. Usually, this is
handled for you by MiniGlFb
, but that isn’t the case when using the
GlutinBreakout
.
Whenever you receive a resize event for your window, make sure to call
Framebuffer::resize_viewport
with the new physical dimensions of your window. You can also
figure out some logical dimensions and call Framebuffer::resize_buffer
too.
Additionally, when managing multiple framebuffers at once, you should make sure to call
GlutinBreakout::make_current
when appropriate, before calling any Framebuffer
methods.
Forgetting to call make_current
can cause OpenGL to get confused and draw to the wrong window,
which is probably not what you want.
Fields (Non-exhaustive)§
This struct is marked as non-exhaustive
Struct { .. }
syntax; cannot be matched against without a wildcard ..
; and struct update syntax will not work.buffer_size: LogicalSize<i32>
The logical size of the buffer. When you update the buffer via
update_buffer
, it is expected to contain
buffer_size.width * buffer_size.height
pixels.
vp_size: PhysicalSize<i32>
The physical size of the viewport. This should always be kept up to date with the size of the window, and there is no reason to set it otherwise unless you’re drawing multiple buffers to one window or something funky like that.
did_draw: bool
This is set to true
every time draw
is called. (or, by extension,
update_buffer
)
It’s safe to set this to false
afterwards, it’s just a flag to let you know if code you’re
calling into has updated the buffer or not.
inverted_y: bool
True if the origin should be the bottom left of the screen instead of the top left. For
historical reasons, this is the default. This should only be configured by changing the
Config
passed to get_fancy
.
internal: FramebufferInternal
Contains internal OpenGL things.
Accessing fields directly is not the intended usage. If a feature is missing please open an issue. The fields are public, however, so that while you are waiting for a feature to be exposed, if you need something in a pinch you can dig in easily and make it happen.
The internal fields may change.
Implementations§
Source§impl Framebuffer
impl Framebuffer
Sourcepub fn update_buffer<T>(&mut self, image_data: &[T])
pub fn update_buffer<T>(&mut self, image_data: &[T])
Examples found in repository?
More examples
10fn main() {
11 let (event_loop, mut fb) = mini_gl_fb::gotta_go_fast("Hello world!", 800.0, 600.0);
12 let mut buffer = vec![[128u8, 0, 0, 255]; 800 * 600];
13 fb.update_buffer(&buffer);
14
15 let GlutinBreakout {
16 context,
17 mut fb,
18 } = fb.glutin_breakout();
19
20 let mut mouse_down = false;
21
22 event_loop.run(move |event, _, flow| {
23 match event {
24 Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
25 *flow = ControlFlow::Exit;
26 }
27 Event::WindowEvent { event: KeyboardInput { input, .. }, .. } => {
28 if let Some(k) = input.virtual_keycode {
29 if k == VirtualKeyCode::Escape && input.state == ElementState::Pressed {
30 *flow = ControlFlow::Exit;
31 }
32 }
33 }
34 Event::WindowEvent { event: WindowEvent::Resized(size), .. } => {
35 context.resize(size);
36 context.window().request_redraw();
37 }
38 Event::WindowEvent { event: WindowEvent::CursorMoved { position, .. }, .. } => {
39 let (x, y) = position.to_logical::<f64>(context.window().scale_factor()).into();
40 println!("({}, {})", x, y);
41 let mouse_x = min(max(x, 0), 800 - 1);
42 let mouse_y = min(max(fb.buffer_size.height - y, 0), 600 - 1);
43 if mouse_down {
44 buffer[(mouse_x + mouse_y * 800) as usize] = [64, 128, 255, 255];
45 fb.update_buffer(&buffer);
46 context.window().request_redraw();
47 }
48 }
49 Event::WindowEvent { event: WindowEvent::MouseInput { state, .. }, .. } => {
50 if state == ElementState::Pressed {
51 mouse_down = true;
52 } else {
53 mouse_down = false;
54 }
55 }
56 Event::RedrawRequested(_) => {
57 fb.redraw();
58 context.swap_buffers().unwrap();
59 }
60 _ => {}
61 }
62 });
63}
18fn main() {
19 let mut event_loop = EventLoop::new();
20 let mut fb = mini_gl_fb::get_fancy(config! {
21 window_title: String::from("PSA: Conway wants you to appreciate group theory instead"),
22 window_size: LogicalSize::new(800.0, 800.0),
23 buffer_size: Some(LogicalSize::new(WIDTH as _, HEIGHT as _))
24 }, &event_loop);
25
26 fb.change_buffer_format::<u8>(BufferFormat::R);
27 fb.use_post_process_shader(POST_PROCESS);
28
29 let mut neighbors = vec![0; WIDTH * HEIGHT];
30 let mut cells = vec![false; WIDTH * HEIGHT];
31
32 cells[5 * WIDTH + 10] = true;
33 cells[5 * WIDTH + 11] = true;
34 cells[5 * WIDTH + 12] = true;
35
36 cells[50 * WIDTH + 50] = true;
37 cells[51 * WIDTH + 51] = true;
38 cells[52 * WIDTH + 49] = true;
39 cells[52 * WIDTH + 50] = true;
40 cells[52 * WIDTH + 51] = true;
41
42 // ID of the Wakeup which means we should update the board
43 let mut update_id: Option<u32> = None;
44
45 fb.glutin_handle_basic_input(&mut event_loop, |fb, input| {
46 // We're going to use wakeups to update the grid
47 input.wait = true;
48
49 if update_id.is_none() {
50 update_id = Some(input.schedule_wakeup(Instant::now() + Duration::from_millis(500)))
51 } else if let Some(mut wakeup) = input.wakeup {
52 if Some(wakeup.id) == update_id {
53 // Time to update our grid
54 calculate_neighbors(&mut cells, &mut neighbors);
55 make_some_babies(&mut cells, &mut neighbors);
56 fb.update_buffer(&cells);
57
58 // Reschedule another update
59 wakeup.when = Instant::now() + Duration::from_millis(
60 if input.key_is_down(VirtualKeyCode::LShift) {
61 TURBO_SPEED
62 } else {
63 NORMAL_SPEED
64 }
65 );
66
67 input.reschedule_wakeup(wakeup);
68 }
69
70 // We will get called again after all wakeups are handled
71 return true;
72 }
73
74 if input.key_is_down(VirtualKeyCode::Escape) {
75 return false;
76 }
77
78 if input.mouse_is_down(MouseButton::Left) || input.mouse_is_down(MouseButton::Right) {
79 // Mouse was pressed
80 let (x, y) = input.mouse_pos;
81 let x = x.min(WIDTH as f64 - 0.0001).max(0.0).floor() as usize;
82 let y = y.min(HEIGHT as f64 - 0.0001).max(0.0).floor() as usize;
83 cells[y * WIDTH + x] = input.mouse_is_down(MouseButton::Left);
84 fb.update_buffer(&cells);
85 // Give the user extra time to make something pretty each time they click
86 if !input.key_is_down(VirtualKeyCode::LShift) {
87 input.adjust_wakeup(update_id.unwrap(), Wakeup::after_millis(2000));
88 }
89 }
90
91 // TODO support right shift. Probably by querying modifiers somehow. (modifiers support)
92 if input.key_pressed(VirtualKeyCode::LShift) {
93 // immediately update
94 input.adjust_wakeup(update_id.unwrap(), Wakeup::after_millis(0));
95 } else if input.key_released(VirtualKeyCode::LShift) {
96 // immediately stop updating
97 input.adjust_wakeup(update_id.unwrap(), Wakeup::after_millis(NORMAL_SPEED));
98 }
99
100 true
101 });
102}
pub fn use_vertex_shader(&mut self, source: &str)
Sourcepub fn use_fragment_shader(&mut self, source: &str)
pub fn use_fragment_shader(&mut self, source: &str)
Examples found in repository?
101fn main() {
102 let width = 800.0;
103 let height = 600.0;
104
105 let (mut event_loop, mut fb) = mini_gl_fb::gotta_go_fast("Hello shaders!", width, height);
106
107 let mut buffer = vec![[128u8, 0, 0, 255]; (width * height) as usize];
108 // let's write a red line into the buffer roughly along the diagonal (misses many pixels)
109 for i in 0..100 {
110 let j = i as f64 / 100.0;
111 let index = (width * j * (height + 1.0)).floor() as usize;
112 buffer[index] = [255, 0, 0, 255];
113 }
114
115 // Let's keep using the default vertex shader
116 // fb.internal.use_vertex_shader(...);
117 fb.internal.fb.use_geometry_shader(GEOMETRY_SOURCE);
118 fb.internal.fb.use_fragment_shader(FRAGMENT_SOURCE);
119
120 fb.update_buffer(&buffer);
121
122 fb.persist_and_redraw(&mut event_loop, true);
123}
pub fn use_post_process_shader(&mut self, source: &str)
Sourcepub fn use_geometry_shader(&mut self, source: &str)
pub fn use_geometry_shader(&mut self, source: &str)
Examples found in repository?
101fn main() {
102 let width = 800.0;
103 let height = 600.0;
104
105 let (mut event_loop, mut fb) = mini_gl_fb::gotta_go_fast("Hello shaders!", width, height);
106
107 let mut buffer = vec![[128u8, 0, 0, 255]; (width * height) as usize];
108 // let's write a red line into the buffer roughly along the diagonal (misses many pixels)
109 for i in 0..100 {
110 let j = i as f64 / 100.0;
111 let index = (width * j * (height + 1.0)).floor() as usize;
112 buffer[index] = [255, 0, 0, 255];
113 }
114
115 // Let's keep using the default vertex shader
116 // fb.internal.use_vertex_shader(...);
117 fb.internal.fb.use_geometry_shader(GEOMETRY_SOURCE);
118 fb.internal.fb.use_fragment_shader(FRAGMENT_SOURCE);
119
120 fb.update_buffer(&buffer);
121
122 fb.persist_and_redraw(&mut event_loop, true);
123}
pub fn use_grayscale_shader(&mut self)
pub fn change_buffer_format<T: ToGlType>(&mut self, format: BufferFormat)
Sourcepub fn resize_buffer(&mut self, buffer_width: u32, buffer_height: u32)
pub fn resize_buffer(&mut self, buffer_width: u32, buffer_height: u32)
Examples found in repository?
101 fn resize(&mut self, new_size: LogicalSize<u32>) {
102 let mut new_buffer = vec![self.bg; new_size.width as usize * new_size.height as usize];
103
104 if self.buffer_size.width > 0 {
105 // use rchunks for inverted y
106 for (old_line, new_line) in self.buffer.chunks_exact(self.buffer_size.width as usize)
107 .zip(new_buffer.chunks_exact_mut(new_size.width as usize)) {
108 if old_line.len() <= new_line.len() {
109 new_line[0..old_line.len()].copy_from_slice(old_line)
110 } else {
111 new_line.copy_from_slice(&old_line[0..new_line.len()])
112 }
113 }
114 }
115
116 self.buffer = new_buffer;
117 self.buffer_size = new_size;
118 self.breakout.fb.resize_buffer(new_size.width, new_size.height);
119 }
Sourcepub fn resize_viewport(&mut self, width: u32, height: u32)
pub fn resize_viewport(&mut self, width: u32, height: u32)
Examples found in repository?
180 fn handle_event(&mut self, event: &Event<()>) -> bool {
181 match *event {
182 Event::WindowEvent {
183 window_id: id,
184 event: WindowEvent::CloseRequested,
185 ..
186 } if self.matches_id(id) => {
187 return false;
188 }
189 Event::WindowEvent {
190 window_id: id,
191 event: WindowEvent::KeyboardInput {
192 input: KeyboardInput {
193 virtual_keycode: Some(VirtualKeyCode::Escape),
194 state: ElementState::Pressed,
195 ..
196 },
197 ..
198 },
199 ..
200 } if self.matches_id(id) => {
201 if let Some(_) = self.window().fullscreen() {
202 self.window().set_fullscreen(None);
203 } else {
204 return false;
205 }
206 }
207 Event::RedrawRequested(id) if self.matches_id(id) => {
208 unsafe { self.breakout.make_current().unwrap(); }
209 self.redraw();
210 }
211 Event::WindowEvent {
212 window_id: id,
213 event: WindowEvent::Resized(size),
214 ..
215 } if self.matches_id(id) => {
216 unsafe { self.breakout.make_current().unwrap(); }
217 self.breakout.fb.resize_viewport(size.width, size.height);
218 self.resize(size.to_logical(self.window().scale_factor() * SCALE_FACTOR));
219 self.request_redraw();
220 }
221 Event::WindowEvent {
222 window_id: id,
223 event: WindowEvent::MouseInput {
224 button: MouseButton::Left,
225 state,
226 ..
227 },
228 ..
229 } if self.matches_id(id) => {
230 self.mouse_state = state;
231 self.line_start = None;
232 }
233 Event::WindowEvent {
234 window_id: id,
235 event: WindowEvent::CursorMoved {
236 position,
237 ..
238 },
239 ..
240 } if self.matches_id(id) => {
241 if self.mouse_state == ElementState::Pressed {
242 let inner_size = self.window().inner_size();
243 let position = LogicalPosition::new(
244 ((position.x / inner_size.width as f64) * self.buffer_size.width as f64).floor(),
245 ((position.y / inner_size.height as f64) * self.buffer_size.height as f64).floor()
246 ).cast::<i32>();
247
248 if let Some(line_start) = self.line_start {
249 self.plot_line(line_start, position);
250 } else {
251 self.plot(position);
252 }
253
254 self.line_start = Some(position);
255
256 self.request_redraw();
257 }
258 }
259 _ => {}
260 }
261
262 true
263 }
Sourcepub fn redraw(&mut self)
pub fn redraw(&mut self)
Examples found in repository?
10fn main() {
11 let (event_loop, mut fb) = mini_gl_fb::gotta_go_fast("Hello world!", 800.0, 600.0);
12 let mut buffer = vec![[128u8, 0, 0, 255]; 800 * 600];
13 fb.update_buffer(&buffer);
14
15 let GlutinBreakout {
16 context,
17 mut fb,
18 } = fb.glutin_breakout();
19
20 let mut mouse_down = false;
21
22 event_loop.run(move |event, _, flow| {
23 match event {
24 Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
25 *flow = ControlFlow::Exit;
26 }
27 Event::WindowEvent { event: KeyboardInput { input, .. }, .. } => {
28 if let Some(k) = input.virtual_keycode {
29 if k == VirtualKeyCode::Escape && input.state == ElementState::Pressed {
30 *flow = ControlFlow::Exit;
31 }
32 }
33 }
34 Event::WindowEvent { event: WindowEvent::Resized(size), .. } => {
35 context.resize(size);
36 context.window().request_redraw();
37 }
38 Event::WindowEvent { event: WindowEvent::CursorMoved { position, .. }, .. } => {
39 let (x, y) = position.to_logical::<f64>(context.window().scale_factor()).into();
40 println!("({}, {})", x, y);
41 let mouse_x = min(max(x, 0), 800 - 1);
42 let mouse_y = min(max(fb.buffer_size.height - y, 0), 600 - 1);
43 if mouse_down {
44 buffer[(mouse_x + mouse_y * 800) as usize] = [64, 128, 255, 255];
45 fb.update_buffer(&buffer);
46 context.window().request_redraw();
47 }
48 }
49 Event::WindowEvent { event: WindowEvent::MouseInput { state, .. }, .. } => {
50 if state == ElementState::Pressed {
51 mouse_down = true;
52 } else {
53 mouse_down = false;
54 }
55 }
56 Event::RedrawRequested(_) => {
57 fb.redraw();
58 context.swap_buffers().unwrap();
59 }
60 _ => {}
61 }
62 });
63}
Sourcepub fn draw<F: FnOnce(&Framebuffer)>(&mut self, f: F)
pub fn draw<F: FnOnce(&Framebuffer)>(&mut self, f: F)
Draw the quad to the active context. Optionally issue other commands after binding everything but before drawing it.
You probably want redraw
(equivalent to .draw(|_| {})
).