
* egui-winit: don't assume window available at init On Android in particular we can only initialize render state once we have a native window, after a 'Resumed' lifecycle event. It's still practical to be able to initialize an egui_winit::State early on so this adds setters for the max_texture_side and pixels_per_point that can be called once we have a valid Window and have initialized a graphics context. On Wayland, where we need to access the Display for clipboard handling we now get the Display from the event loop instead of a window. * egui-wgpu: lazily initialize render + surface state Enable the renderer and surface state initialization to be deferred until we know that any winit window we created has a valid native window and enable the surface state to be updated in case the native window changes. In particular these changes help with running on Android where winit windows will only have a valid native window associated with them between Resumed and Paused lifecycle events, and so surface creation (and render state initialization) needs to wait until the first Resumed event, and the surface needs to be dropped/recreated based on Paused/Resumed events.
127 lines
4.7 KiB
Rust
127 lines
4.7 KiB
Rust
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
|
|
|
use glium::glutin;
|
|
|
|
fn main() {
|
|
let event_loop = glutin::event_loop::EventLoop::with_user_event();
|
|
let display = create_display(&event_loop);
|
|
|
|
let mut egui_glium = egui_glium::EguiGlium::new(&display, &event_loop);
|
|
|
|
let png_data = include_bytes!("../../examples/retained_image/src/rust-logo-256x256.png");
|
|
let image = load_glium_image(png_data);
|
|
let image_size = egui::Vec2::new(image.width as f32, image.height as f32);
|
|
// Load to gpu memory
|
|
let glium_texture = glium::texture::SrgbTexture2d::new(&display, image).unwrap();
|
|
// Allow us to share the texture with egui:
|
|
let glium_texture = std::rc::Rc::new(glium_texture);
|
|
// Allocate egui's texture id for GL texture
|
|
let texture_id = egui_glium.painter.register_native_texture(glium_texture);
|
|
// Setup button image size for reasonable image size for button container.
|
|
let button_image_size = egui::Vec2::new(32_f32, 32_f32);
|
|
|
|
event_loop.run(move |event, _, control_flow| {
|
|
let mut redraw = || {
|
|
let mut quit = false;
|
|
|
|
let needs_repaint = egui_glium.run(&display, |egui_ctx| {
|
|
egui::SidePanel::left("my_side_panel").show(egui_ctx, |ui| {
|
|
if ui
|
|
.add(egui::Button::image_and_text(
|
|
texture_id,
|
|
button_image_size,
|
|
"Quit",
|
|
))
|
|
.clicked()
|
|
{
|
|
quit = true;
|
|
}
|
|
});
|
|
egui::Window::new("NativeTextureDisplay").show(egui_ctx, |ui| {
|
|
ui.image(texture_id, image_size);
|
|
});
|
|
});
|
|
|
|
*control_flow = if quit {
|
|
glutin::event_loop::ControlFlow::Exit
|
|
} else if needs_repaint {
|
|
display.gl_window().window().request_redraw();
|
|
glutin::event_loop::ControlFlow::Poll
|
|
} else {
|
|
glutin::event_loop::ControlFlow::Wait
|
|
};
|
|
|
|
{
|
|
use glium::Surface as _;
|
|
let mut target = display.draw();
|
|
|
|
let color = egui::Rgba::from_rgb(0.1, 0.3, 0.2);
|
|
target.clear_color(color[0], color[1], color[2], color[3]);
|
|
|
|
// draw things behind egui here
|
|
|
|
egui_glium.paint(&display, &mut target);
|
|
|
|
// draw things on top of egui here
|
|
|
|
target.finish().unwrap();
|
|
}
|
|
};
|
|
|
|
match event {
|
|
// Platform-dependent event handlers to workaround a winit bug
|
|
// See: https://github.com/rust-windowing/winit/issues/987
|
|
// See: https://github.com/rust-windowing/winit/issues/1619
|
|
glutin::event::Event::RedrawEventsCleared if cfg!(windows) => redraw(),
|
|
glutin::event::Event::RedrawRequested(_) if !cfg!(windows) => redraw(),
|
|
|
|
glutin::event::Event::WindowEvent { event, .. } => {
|
|
use glutin::event::WindowEvent;
|
|
if matches!(event, WindowEvent::CloseRequested | WindowEvent::Destroyed) {
|
|
*control_flow = glutin::event_loop::ControlFlow::Exit;
|
|
}
|
|
|
|
egui_glium.on_event(&event);
|
|
|
|
display.gl_window().window().request_redraw(); // TODO(emilk): ask egui if the events warrants a repaint instead
|
|
}
|
|
|
|
_ => (),
|
|
}
|
|
});
|
|
}
|
|
|
|
fn create_display(event_loop: &glutin::event_loop::EventLoop<()>) -> glium::Display {
|
|
let window_builder = glutin::window::WindowBuilder::new()
|
|
.with_resizable(true)
|
|
.with_inner_size(glutin::dpi::LogicalSize {
|
|
width: 800.0,
|
|
height: 600.0,
|
|
})
|
|
.with_title("egui_glium example");
|
|
|
|
let context_builder = glutin::ContextBuilder::new()
|
|
.with_depth_buffer(0)
|
|
.with_srgb(true)
|
|
.with_stencil_buffer(0)
|
|
.with_vsync(true);
|
|
|
|
glium::Display::new(window_builder, context_builder, event_loop).unwrap()
|
|
}
|
|
|
|
fn load_glium_image(png_data: &[u8]) -> glium::texture::RawImage2d<'_, u8> {
|
|
// Load image using the image crate:
|
|
let image = image::load_from_memory(png_data).unwrap().to_rgba8();
|
|
let image_dimensions = image.dimensions();
|
|
|
|
// Premultiply alpha:
|
|
let pixels: Vec<_> = image
|
|
.into_vec()
|
|
.chunks_exact(4)
|
|
.map(|p| egui::Color32::from_rgba_unmultiplied(p[0], p[1], p[2], p[3]))
|
|
.flat_map(|color| color.to_array())
|
|
.collect();
|
|
|
|
// Convert to glium image:
|
|
glium::texture::RawImage2d::from_raw_rgba(pixels, image_dimensions)
|
|
}
|