diff --git a/imgui-winit-glow-renderer-viewports/examples/basic.rs b/imgui-winit-glow-renderer-viewports/examples/basic.rs index 37c9a43..e8af25f 100644 --- a/imgui-winit-glow-renderer-viewports/examples/basic.rs +++ b/imgui-winit-glow-renderer-viewports/examples/basic.rs @@ -1,4 +1,4 @@ -use std::{ffi::CString, num::NonZeroU32}; +use std::{ffi::CString, num::NonZeroU32, time::Instant}; use glow::{Context, HasContext}; use glutin::{ @@ -12,7 +12,7 @@ use glutin_winit::DisplayBuilder; use imgui::ConfigFlags; use imgui_winit_glow_renderer_viewports::Renderer; use raw_window_handle::HasRawWindowHandle; -use winit::{dpi::LogicalSize, event_loop::EventLoop, window::WindowBuilder}; +use winit::{dpi::LogicalSize, event_loop::EventLoop, window::WindowBuilder, event::WindowEvent}; fn main() { let event_loop = EventLoop::new(); @@ -74,22 +74,38 @@ fn main() { .io_mut() .config_flags .insert(ConfigFlags::VIEWPORTS_ENABLE); + imgui.set_ini_filename(None); let mut renderer = Renderer::new(&mut imgui, &window, &glow).expect("Failed to init Renderer"); + let mut last_frame = Instant::now(); + event_loop.run(move |event, window_target, control_flow| { control_flow.set_poll(); renderer.handle_event(&mut imgui, &window, &event); match event { + winit::event::Event::NewEvents(_) => { + let now = Instant::now(); + imgui.io_mut().update_delta_time(now - last_frame); + last_frame = now; + }, + winit::event::Event::WindowEvent { window_id, event: WindowEvent::CloseRequested } if window_id == window.id() => { + control_flow.set_exit(); + }, winit::event::Event::MainEventsCleared => { window.request_redraw(); }, winit::event::Event::RedrawRequested(_) => { let ui = imgui.frame(); + ui.dockspace_over_main_viewport(); + ui.show_demo_window(&mut true); + ui.window("Style Editor").build(|| { + ui.show_default_style_editor(); + }); ui.end_frame_early(); @@ -98,9 +114,14 @@ fn main() { let draw_data = imgui.render(); - context.make_current(&surface).expect("Failed to make current"); + if let Err(e) = context.make_current(&surface) { + // For some reason make_current randomly throws errors on windows. + // Until the reason for this is found, we just print it out instead of panicing. + eprintln!("Failed to make current: {e}"); + } unsafe { + glow.disable(glow::SCISSOR_TEST); glow.clear(glow::COLOR_BUFFER_BIT); } diff --git a/imgui-winit-glow-renderer-viewports/src/lib.rs b/imgui-winit-glow-renderer-viewports/src/lib.rs index 59e97e1..e5820ae 100644 --- a/imgui-winit-glow-renderer-viewports/src/lib.rs +++ b/imgui-winit-glow-renderer-viewports/src/lib.rs @@ -3,7 +3,8 @@ use std::{ collections::{HashMap, VecDeque}, num::NonZeroU32, ptr::null_mut, - rc::Rc, slice, + rc::Rc, + slice, }; use glow::HasContext; @@ -12,7 +13,7 @@ use glutin::{ context::{ContextAttributesBuilder, NotCurrentContext}, display::GetGlDisplay, prelude::{GlDisplay, NotCurrentGlContextSurfaceAccessor, PossiblyCurrentGlContext}, - surface::{Surface, SurfaceAttributesBuilder, WindowSurface, GlSurface}, + surface::{GlSurface, Surface, SurfaceAttributesBuilder, WindowSurface}, }; use glutin_winit::DisplayBuilder; use imgui::{BackendFlags, Id, Key, ViewportFlags}; @@ -160,22 +161,6 @@ impl GlObjects { tex }; - let vao = unsafe { - let vao = glow - .create_vertex_array() - .map_err(|e| RendererError::GlObjectCreationError(e))?; - - glow.bind_vertex_array(Some(vao)); - glow.enable_vertex_attrib_array(0); - glow.enable_vertex_attrib_array(1); - glow.enable_vertex_attrib_array(2); - glow.vertex_attrib_pointer_f32(0, 2, glow::FLOAT, false, 20, 0); - glow.vertex_attrib_pointer_f32(0, 2, glow::FLOAT, false, 20, 8); - glow.vertex_attrib_pointer_f32(0, 4, glow::UNSIGNED_BYTE, true, 20, 16); - - vao - }; - let vbo = unsafe { glow.create_buffer() .map_err(|e| RendererError::GlObjectCreationError(e))? @@ -185,6 +170,25 @@ impl GlObjects { .map_err(|e| RendererError::GlObjectCreationError(e))? }; + let vao = unsafe { + let vao = glow + .create_vertex_array() + .map_err(|e| RendererError::GlObjectCreationError(e))?; + + glow.bind_vertex_array(Some(vao)); + glow.bind_buffer(glow::ARRAY_BUFFER, Some(vbo)); + glow.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(ibo)); + glow.enable_vertex_attrib_array(0); + glow.enable_vertex_attrib_array(1); + glow.enable_vertex_attrib_array(2); + glow.vertex_attrib_pointer_f32(0, 2, glow::FLOAT, false, 20, 0); + glow.vertex_attrib_pointer_f32(1, 2, glow::FLOAT, false, 20, 8); + glow.vertex_attrib_pointer_f32(2, 4, glow::UNSIGNED_BYTE, true, 20, 16); + glow.bind_vertex_array(None); + + vao + }; + Ok(Self { program, font_texture, @@ -295,7 +299,7 @@ impl Renderer { gl_objects, glutin_config: None, extra_windows: HashMap::new(), - event_queue: Rc::new(RefCell::new(VecDeque::new())), + event_queue, font_width: font_tex.width, font_height: font_tex.height, font_pixels: font_tex.data.to_vec(), @@ -313,18 +317,20 @@ impl Renderer { window_id, ref event, } => { - let viewport = if window_id == main_window.id() { - imgui.main_viewport_mut() + let (window, viewport) = if window_id == main_window.id() { + (main_window, imgui.main_viewport_mut()) } else { - if let Some(id) = self.extra_windows.iter().find_map(|(id, (wnd, _, _, _))| { - if wnd.id() == window_id { - Some(*id) - } else { - None - } - }) { + if let Some((id, wnd)) = + self.extra_windows.iter().find_map(|(id, (wnd, _, _, _))| { + if wnd.id() == window_id { + Some((*id, wnd)) + } else { + None + } + }) + { if let Some(viewport) = imgui.viewport_by_id_mut(id) { - viewport + (wnd, viewport) } else { return; } @@ -335,18 +341,21 @@ impl Renderer { match *event { winit::event::WindowEvent::Resized(new_size) => { - viewport.size = [new_size.width as f32, new_size.height as f32]; - viewport.work_size = viewport.size; + unsafe { + (*(viewport.platform_user_data.cast::())).size = + [new_size.width as f32, new_size.height as f32]; + } if window_id == main_window.id() { imgui.io_mut().display_size = [new_size.width as f32, new_size.height as f32]; } } - winit::event::WindowEvent::Moved(new_pos) => { - viewport.pos = [new_pos.x as f32, new_pos.y as f32]; - viewport.work_pos = viewport.pos; - } + winit::event::WindowEvent::Moved(_) => unsafe { + let new_pos = window.inner_position().unwrap().cast::(); + (*(viewport.platform_user_data.cast::())).pos = + [new_pos.x as f32, new_pos.y as f32]; + }, winit::event::WindowEvent::CloseRequested if window_id != main_window.id() => { viewport.platform_request_close = true; } @@ -368,7 +377,11 @@ impl Renderer { imgui.io_mut().keys_down[key as usize] = true; } winit::event::WindowEvent::CursorMoved { position, .. } => { - imgui.io_mut().mouse_pos = [position.x as f32, position.y as f32]; + let window_pos = window.inner_position().unwrap().cast::(); + imgui.io_mut().mouse_pos = [ + position.x as f32 + window_pos.x, + position.y as f32 + window_pos.y, + ]; } winit::event::WindowEvent::MouseWheel { delta, @@ -582,13 +595,20 @@ impl Renderer { ) -> Result<(), RendererError> { for (id, (wnd, context, surface, gl_objects)) in &mut self.extra_windows { if let Some(viewport) = imgui.viewport_by_id(*id) { - let current_context = context.take().unwrap().make_current(surface).map_err(|_| RendererError::GlutinDisplay)?; + let current_context = context + .take() + .unwrap() + .make_current(surface) + .map_err(|_| RendererError::GlutinDisplay)?; unsafe { + glow.disable(glow::SCISSOR_TEST); glow.clear(glow::COLOR_BUFFER_BIT); } Self::render_window(wnd, glow, viewport.draw_data(), gl_objects)?; - surface.swap_buffers(¤t_context).map_err(|_| RendererError::GlutinDisplay)?; + surface + .swap_buffers(¤t_context) + .map_err(|_| RendererError::GlutinDisplay)?; *context = Some(current_context.make_not_current().unwrap()); } @@ -608,6 +628,10 @@ impl Renderer { glow.viewport(0, 0, window_size.width as i32, window_size.height as i32); + glow.enable(glow::BLEND); + glow.blend_func(glow::SRC_ALPHA, glow::ONE_MINUS_SRC_ALPHA); + glow.enable(glow::SCISSOR_TEST); + glow.bind_vertex_array(Some(gl_objects.vao)); glow.bind_buffer(glow::ARRAY_BUFFER, Some(gl_objects.vbo)); glow.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(gl_objects.ibo)); @@ -619,28 +643,67 @@ impl Renderer { let right = draw_data.display_pos[0] + draw_data.display_size[0]; let top = draw_data.display_pos[1]; let bottom = draw_data.display_pos[1] + draw_data.display_size[1]; - let matrix = [ - 2.0 / (right - left) , 0.0 , 0.0 , 0.0, - 0.0 , (2.0 / (top - bottom)) , 0.0 , 0.0, - 0.0 , 0.0 , -1.0, 0.0, - (right + left) / (left - right), (top + bottom) / (bottom - top), 0.0 , 1.0, + 2.0 / (right - left), + 0.0, + 0.0, + 0.0, + 0.0, + (2.0 / (top - bottom)), + 0.0, + 0.0, + 0.0, + 0.0, + -1.0, + 0.0, + (right + left) / (left - right), + (top + bottom) / (bottom - top), + 0.0, + 1.0, ]; - let loc = glow.get_uniform_location(gl_objects.program, "u_Matrix").unwrap(); + let loc = glow + .get_uniform_location(gl_objects.program, "u_Matrix") + .unwrap(); glow.uniform_matrix_4_f32_slice(Some(&loc), false, &matrix); for list in draw_data.draw_lists() { - glow.buffer_data_u8_slice(glow::ARRAY_BUFFER, slice::from_raw_parts(list.vtx_buffer().as_ptr().cast(), list.vtx_buffer().len() * 20), glow::STREAM_DRAW); - glow.buffer_data_u8_slice(glow::ELEMENT_ARRAY_BUFFER, slice::from_raw_parts(list.idx_buffer().as_ptr().cast(), list.idx_buffer().len() * 2), glow::STREAM_DRAW); + glow.buffer_data_u8_slice( + glow::ARRAY_BUFFER, + slice::from_raw_parts( + list.vtx_buffer().as_ptr().cast(), + list.vtx_buffer().len() * 20, + ), + glow::STREAM_DRAW, + ); + glow.buffer_data_u8_slice( + glow::ELEMENT_ARRAY_BUFFER, + slice::from_raw_parts( + list.idx_buffer().as_ptr().cast(), + list.idx_buffer().len() * 2, + ), + glow::STREAM_DRAW, + ); for cmd in list.commands() { match cmd { imgui::DrawCmd::Elements { count, cmd_params } => { - glow.draw_elements_base_vertex(glow::TRIANGLES, count as i32, glow::UNSIGNED_SHORT, (cmd_params.idx_offset * 2) as i32, cmd_params.vtx_offset as i32); - }, - _ => {}, + let clip_x1 = (cmd_params.clip_rect[0] - draw_data.display_pos[0]) as i32; + let clip_y1 = (cmd_params.clip_rect[1] - draw_data.display_pos[1]) as i32; + let clip_x2 = (cmd_params.clip_rect[2] - draw_data.display_pos[0]) as i32; + let clip_y2 = (cmd_params.clip_rect[3] - draw_data.display_pos[1]) as i32; + + glow.scissor(clip_x1, window_size.height as i32 - clip_y2, clip_x2 - clip_x1, clip_y2 - clip_y1); + glow.draw_elements_base_vertex( + glow::TRIANGLES, + count as i32, + glow::UNSIGNED_SHORT, + (cmd_params.idx_offset * 2) as i32, + cmd_params.vtx_offset as i32, + ); + } + _ => {} } } }