Struct mini_gl_fb::breakout::GlutinBreakout [−][src]
GlutinBreakout
is useful when you are growing out of the basic input methods and synchronous
nature of MiniGlFb
, since it's more powerful than the the higher-level
abstrations. You can obtain it by calling
MiniGlFb::glutin_breakout()
.
Usage for multiple windows
The basic idea for managing multiple windows is to check each incoming event to determine which
window it's for. In order to draw to multiple windows individually, you have to switch the
context using make_current
before updating the window.
Here's a basic implementation (there's a lot of boilerplate because we're not using the
MiniGlFb
API - it's closer to using
winit
directly):
use mini_gl_fb::GlutinBreakout; use mini_gl_fb::glutin::window::{Window, WindowId}; use mini_gl_fb::glutin::event::{Event, WindowEvent, KeyboardInput, VirtualKeyCode, ElementState}; use mini_gl_fb::glutin::event_loop::{EventLoop, ControlFlow}; use mini_gl_fb::config; struct TrackedWindow { pub breakout: GlutinBreakout, pub background: [u8; 4] } impl TrackedWindow { fn window(&self) -> &Window { self.breakout.context.window() } fn matches_id(&self, id: WindowId) -> bool { id == self.breakout.context.window().id() } pub fn handle_event(&mut self, event: &Event<()>) -> bool { match event { Event::WindowEvent { window_id: id, event, .. } if self.matches_id(*id) => { match event { WindowEvent::CloseRequested | WindowEvent::KeyboardInput { input: KeyboardInput { virtual_keycode: Some(VirtualKeyCode::Escape), state: ElementState::Pressed, .. }, .. } => return false, WindowEvent::Resized(size) => { self.breakout.fb.resize_viewport(size.width, size.height); let size = size.to_logical(self.window().scale_factor()); self.breakout.fb.resize_buffer(size.width, size.height); } _ => { // do other stuff? } } } Event::RedrawRequested(id) if self.matches_id(*id) => { // If you don't do this, OpenGL will get confused and only draw to one window. unsafe { self.breakout.make_current().unwrap(); } let size = self.window().inner_size().to_logical::<f64>(self.window().scale_factor()); // Unfortunately the performance of this is abysmal. Usually you should cache // your buffer and only update it when needed or when the window is resized. let pixels = size.width.floor() as usize * size.height.floor() as usize; self.breakout.fb.update_buffer(&vec![self.background; pixels]); self.breakout.context.swap_buffers(); } _ => {} } true } } fn main() { let event_loop = EventLoop::new(); let mut windows: Vec<Option<TrackedWindow>> = vec![]; let config = config! { resizable: true }; windows.push(Some(TrackedWindow { breakout: mini_gl_fb::get_fancy(config.clone(), &event_loop).glutin_breakout(), background: [224u8, 66, 26, 255] })); windows.push(Some(TrackedWindow { breakout: mini_gl_fb::get_fancy(config.clone(), &event_loop).glutin_breakout(), background: [26u8, 155, 224, 255] })); // run event loop event_loop.run(move |event, _, flow| { *flow = ControlFlow::Wait; for option in &mut windows { if let Some(window) = option { if !window.handle_event(&event) { option.take(); } } } windows.retain(Option::is_some); if windows.is_empty() { *flow = ControlFlow::Exit; } }) }
It's hard to come up with a generalized, flexible implementation of this, especially if you need to open more windows based on user input, or run tasks in other threads, etc. Basically, it's open for you to play with, but it's not functionality that MGlFb wants to include first-class just yet.
Fields
context: WindowedContext<PossiblyCurrent>
Contains the OpenGL context and its associated window. This is a
glutin
struct; go see their documentation on
WindowedContext
for more information.
fb: Framebuffer
Contains the Framebuffer
for that context. Consult its documentation for information on
how to use it.
Implementations
impl GlutinBreakout
[src]
pub unsafe fn make_current(&mut self) -> Result<(), ContextError>
[src]
Sets the current thread's OpenGL context to the one contained in this breakout.
Historically, MGlFb did not support multiple windows. It owned its own event loop and you weren't allowed to use the library with your own. However, as of version 0.8, you are now expected to bring your own event loop to all functions that involve one. This means that multiple windows are very possible, and even supported, as long as you're willing to route events yourself... and manage all the OpenGL contexts.
The problem with managing multiple OpenGL contexts from one thread is that the "current" context is set per-thread. That means you basically have to switch through them really quickly if you want to update multiple windows in "parallel". But how do you switch?
Glutin has you partially covered on this one - it has
make_current
. However,
that method takes self
and emits a new WindowedContext
, and you can't really move self
into that function without unsafe code.
Here is an unsafe function containing code that makes the context current, in-place. That way, you can switch contexts in one line of code, and focus on other stuff.
Usage
event_loop.run(move |event, _, flow| { match event { // ... Event::RedrawRequested(..) => { unsafe { breakout.make_current().unwrap(); } // ... breakout.fb.update_buffer(&your_buffer_here); breakout.context.swap_buffers(); } // ... } })
Trait Implementations
Auto Trait Implementations
impl !RefUnwindSafe for GlutinBreakout
impl !Send for GlutinBreakout
impl !Sync for GlutinBreakout
impl Unpin for GlutinBreakout
impl !UnwindSafe for GlutinBreakout
Blanket Implementations
impl<T> Any for T where
T: 'static + ?Sized,
[src]
T: 'static + ?Sized,
impl<T> Borrow<T> for T where
T: ?Sized,
[src]
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]
T: ?Sized,
pub fn borrow_mut(&mut self) -> &mut T
[src]
impl<T> From<T> for T
[src]
impl<T, U> Into<U> for T where
U: From<T>,
[src]
U: From<T>,
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]
U: Into<T>,
type Error = Infallible
The type returned in the event of a conversion error.
pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]
impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]
U: TryFrom<T>,