use pixels::{wgpu, PixelsContext};
use std::process::abort;
use std::time::Instant;
use pixels::{Error, Pixels, SurfaceTexture};
use winit::dpi::LogicalSize;
use winit::event::{Event, VirtualKeyCode};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::WindowBuilder;
use winit_input_helper::WinitInputHelper;
pub(crate) struct Gui {
imgui: imgui::Context,
platform: imgui_winit_support::WinitPlatform,
renderer: imgui_wgpu::Renderer,
last_frame: Instant,
last_cursor: Option<imgui::MouseCursor>,
open_file_dialog: bool,
}
impl Gui {
pub(crate) fn new(window: &winit::window::Window, pixels: &pixels::Pixels) -> Self {
let mut imgui = imgui::Context::create();
imgui.set_ini_filename(None);
let mut platform = imgui_winit_support::WinitPlatform::init(&mut imgui);
platform.attach_window(
imgui.io_mut(),
window,
imgui_winit_support::HiDpiMode::Default,
);
let hidpi_factor = window.scale_factor();
let font_size = (13.0 * hidpi_factor) as f32;
imgui.io_mut().font_global_scale = (1.0 / hidpi_factor) as f32;
imgui
.fonts()
.add_font(&[imgui::FontSource::DefaultFontData {
config: Some(imgui::FontConfig {
oversample_h: 1,
pixel_snap_h: true,
size_pixels: font_size,
..Default::default()
}),
}]);
let device = pixels.device();
let queue = pixels.queue();
let config = imgui_wgpu::RendererConfig {
texture_format: pixels.render_texture_format(),
..Default::default()
};
let renderer = imgui_wgpu::Renderer::new(&mut imgui, device, queue, config);
Self {
open_file_dialog: true,
imgui,
platform,
renderer,
last_frame: Instant::now(),
last_cursor: None,
}
}
pub(crate) fn prepare(
&mut self,
window: &winit::window::Window,
) -> Result<(), winit::error::ExternalError> {
let now = Instant::now();
self.imgui.io_mut().update_delta_time(now - self.last_frame);
self.last_frame = now;
self.platform.prepare_frame(self.imgui.io_mut(), window)
}
pub(crate) fn render(
&mut self,
window: &winit::window::Window,
encoder: &mut wgpu::CommandEncoder,
render_target: &wgpu::TextureView,
context: &PixelsContext,
) -> imgui_wgpu::RendererResult<()> {
let ui = self.imgui.new_frame();
let mouse_cursor = ui.mouse_cursor();
if self.last_cursor != mouse_cursor {
self.last_cursor = mouse_cursor;
self.platform.prepare_render(ui, window);
}
if self.open_file_dialog == true {
if let Some(file) = imfile::FileDialog::new()
.accept_text("Open file")
.for_save()
.cancel_text("Close")
.title("Open File")
.spawn(&ui)
{
println!("Filename: {}", file.display());
self.open_file_dialog = false;
}
}
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("imgui"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: render_target,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Load,
store: true,
},
})],
depth_stencil_attachment: None,
});
self.renderer.render(
self.imgui.render(),
&context.queue,
&context.device,
&mut rpass,
)
}
pub(crate) fn handle_event(
&mut self,
window: &winit::window::Window,
event: &winit::event::Event<()>,
) {
self.platform
.handle_event(self.imgui.io_mut(), window, event);
}
}
fn main() -> Result<(), Error> {
env_logger::init();
let event_loop = EventLoop::new();
let mut input = WinitInputHelper::new();
let window = {
let size = LogicalSize::new(1280 as f64, 720 as f64);
WindowBuilder::new()
.with_title("ImFile example")
.with_inner_size(size)
.with_min_inner_size(size)
.build(&event_loop)
.unwrap()
};
let mut scale_factor = window.scale_factor();
let mut pixels = {
let window_size = window.inner_size();
let surface_texture = SurfaceTexture::new(window_size.width, window_size.height, &window);
Pixels::new(1280, 720, surface_texture)?
};
let mut gui = Gui::new(&window, &pixels);
event_loop.run(move |event, _, control_flow| {
if let Event::RedrawRequested(_) = event {
pixels.frame_mut().into_iter().for_each(|pix| *pix = 0x0);
gui.prepare(&window).expect("gui.prepare() failed");
let render_result = pixels.render_with(|encoder, render_target, context| {
context.scaling_renderer.render(encoder, render_target);
gui.render(&window, encoder, render_target, context)?;
Ok(())
});
if render_result.is_err() {
log::error!("Can't render!");
abort();
}
}
gui.handle_event(&window, &event);
if input.update(&event) {
if input.key_pressed(VirtualKeyCode::Escape) || input.quit() {
*control_flow = ControlFlow::Exit;
return;
}
if let Some(factor) = input.scale_factor() {
scale_factor = factor;
}
if let Some(size) = input.window_resized() {
if size.width > 0 && size.height > 0 {
pixels.resize_surface(size.width, size.height).expect("resize error");
let LogicalSize { width, height } = size.to_logical(scale_factor);
if let Err(err) = pixels.resize_buffer(width, height) {
panic!("Error: {err}");
}
}
}
window.request_redraw();
}
});
}