From 4b307a1bf7249c50d13b1740c68495231cd028a5 Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Tue, 22 Feb 2022 16:07:58 +0100 Subject: [PATCH 01/42] Added basic Viewport structs and flags --- imgui-examples/Cargo.toml | 2 +- imgui-examples/examples/viewports.rs | 4 ++ imgui/src/context.rs | 14 +++- imgui/src/io.rs | 95 +++++++++++++++++++++++++++- 4 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 imgui-examples/examples/viewports.rs diff --git a/imgui-examples/Cargo.toml b/imgui-examples/Cargo.toml index 0f2fba6..639b0ba 100644 --- a/imgui-examples/Cargo.toml +++ b/imgui-examples/Cargo.toml @@ -13,6 +13,6 @@ publish = false clipboard = "0.5" glium = { version = "0.31", default-features = true } image = "0.23" -imgui = { path = "../imgui", features = ["tables-api"] } +imgui = { path = "../imgui", features = ["tables-api", "docking"] } imgui-glium-renderer = { path = "../imgui-glium-renderer" } imgui-winit-support = { path = "../imgui-winit-support" } diff --git a/imgui-examples/examples/viewports.rs b/imgui-examples/examples/viewports.rs new file mode 100644 index 0000000..3783460 --- /dev/null +++ b/imgui-examples/examples/viewports.rs @@ -0,0 +1,4 @@ + +fn main() { + +} diff --git a/imgui/src/context.rs b/imgui/src/context.rs index de346a8..8964f56 100644 --- a/imgui/src/context.rs +++ b/imgui/src/context.rs @@ -9,7 +9,7 @@ use crate::clipboard::{ClipboardBackend, ClipboardContext}; use crate::fonts::atlas::{FontAtlas, FontId, SharedFontAtlas}; use crate::io::Io; use crate::style::Style; -use crate::{sys, DrawData}; +use crate::{sys, DrawData, PlatformIo}; use crate::{MouseCursor, Ui}; /// An imgui-rs context. @@ -479,6 +479,18 @@ impl Context { &mut *(sys::igGetIO() as *mut Io) } } + pub fn platform_io(&self) -> &PlatformIo { + unsafe { + // safe because PlatformIo is a transparent wrapper around sys::ImGuiPlatformIO + &*(sys::igGetPlatformIO() as *const PlatformIo) + } + } + pub fn platform_io_mut(&mut self) -> &PlatformIo { + unsafe { + // safe because PlatformIo is a transparent wrapper around sys::ImGuiPlatformIO + &mut *(sys::igGetPlatformIO() as *mut PlatformIo) + } + } /// Returns an immutable reference to the user interface style #[doc(alias = "GetStyle")] pub fn style(&self) -> &Style { diff --git a/imgui/src/io.rs b/imgui/src/io.rs index 2362c31..d4c4e92 100644 --- a/imgui/src/io.rs +++ b/imgui/src/io.rs @@ -1,7 +1,7 @@ use bitflags::bitflags; use std::f32; use std::ops::{Index, IndexMut}; -use std::os::raw::{c_char, c_void}; +use std::os::raw::{c_char, c_void, c_int}; use std::time::Duration; use crate::fonts::atlas::FontAtlas; @@ -55,6 +55,27 @@ bitflags! { #[cfg(feature = "docking")] const DOCKING_ENABLE = sys::ImGuiConfigFlags_DockingEnable; + + #[cfg(feature = "docking")] + const VIEWPORTS_ENABLE = sys::ImGuiConfigFlags_ViewportsEnable; + } + + #[cfg(feature = "docking")] + #[repr(transparent)] + pub struct ViewportFlags: u32 { + const IS_PLATFORM_WINDOW = sys::ImGuiViewportFlags_IsPlatformWindow; + const IS_PLATFORM_MONITOR = sys::ImGuiViewportFlags_IsPlatformMonitor; + const OWNED_BY_APP = sys::ImGuiViewportFlags_OwnedByApp; + const NO_DECORATION = sys::ImGuiViewportFlags_NoDecoration; + const NO_TASK_BAR_ICON = sys::ImGuiViewportFlags_NoTaskBarIcon; + const NO_FOCUS_ON_APPEARING = sys::ImGuiViewportFlags_NoFocusOnAppearing; + const NO_FOCUS_ON_CLICK = sys::ImGuiViewportFlags_NoFocusOnClick; + const NO_INPUTS = sys::ImGuiViewportFlags_NoInputs; + const NO_RENDERER_CLEAR = sys::ImGuiViewportFlags_NoRendererClear; + const TOP_MOST = sys::ImGuiViewportFlags_TopMost; + const MINIMIZED = sys::ImGuiViewportFlags_Minimized; + const NO_AUTO_MERGE = sys::ImGuiViewportFlags_NoAutoMerge; + const CAN_HOST_OTHER_WINDOWS = sys::ImGuiViewportFlags_CanHostOtherWindows; } } @@ -74,6 +95,11 @@ bitflags! { /// /// This enables output of large meshes (64K+ vertices) while still using 16-bits indices. const RENDERER_HAS_VTX_OFFSET = sys::ImGuiBackendFlags_RendererHasVtxOffset; + + #[cfg(feature = "docking")] + const PLATFORM_HAS_VIEWPORTS = sys::ImGuiBackendFlags_PlatformHasViewports; + #[cfg(feature = "docking")] + const RENDERER_HAS_VIEWPORTS = sys::ImGuiBackendFlags_RendererHasViewports; } } @@ -132,6 +158,73 @@ fn test_nav_input_variants() { } } +#[cfg(feature = "docking")] +#[repr(C)] +pub struct PlatformIo { + pub(crate) platform_create_window: Option, + pub(crate) platform_destroy_window: Option, + pub(crate) platform_show_window: Option, + pub(crate) platform_set_window_pos: Option, + pub(crate) platform_get_window_pos: Option sys::ImVec2>, + pub(crate) platform_set_window_size: Option, + pub(crate) platform_get_window_size: Option sys::ImVec2>, + pub(crate) platform_set_window_focus: Option, + pub(crate) platform_get_window_focus: Option bool>, + pub(crate) platform_get_window_minimized: Option bool>, + pub(crate) platform_set_window_title: Option, + pub(crate) platform_set_window_alpha: Option, + pub(crate) platform_update_window: Option, + pub(crate) platform_render_window: Option, + pub(crate) platform_swap_buffers: Option, + pub(crate) platform_get_window_dpi_scale: Option f32>, + pub(crate) platform_on_changed_viewport: Option, + pub(crate) platform_create_vk_surface: Option c_int>, + + pub(crate) renderer_create_window: Option, + pub(crate) renderer_destroy_window: Option, + pub(crate) renderer_set_window_size: Option, + pub(crate) renderer_render_window: Option, + pub(crate) renderer_swap_buffers: Option, + + pub(crate) monitors: ImVector, + + pub(crate) viewports: ImVector<*mut Viewport>, +} + +unsafe impl RawCast for PlatformIo {} + +#[cfg(feature = "docking")] +#[repr(C)] +pub struct Viewport { + pub(crate) id: crate::Id, + pub(crate) flags: ViewportFlags, + pub(crate) pos: [f32; 2], + pub(crate) size: [f32; 2], + pub(crate) work_pos: [f32; 2], + pub(crate) work_size: [f32; 2], + pub(crate) dpi_scale: f32, + pub(crate) parent_viewport_id: crate::Id, + pub(crate) draw_data: *mut crate::DrawData, + + pub(crate) renderer_user_data: *mut c_void, + pub(crate) platform_user_data: *mut c_void, + pub(crate) platform_handle: *mut c_void, + pub(crate) platform_handle_raw: *mut c_void, + pub(crate) platform_request_move: bool, + pub(crate) platform_request_resize: bool, + pub(crate) platform_request_close: bool, +} + +#[cfg(feature = "docking")] +#[repr(C)] +pub struct PlatformMonitor { + main_pos: [f32; 2], + main_size: [f32; 2], + work_pos: [f32; 2], + work_size: [f32; 2], + dpi_scale: f32, +} + /// Settings and inputs/outputs for imgui-rs #[repr(C)] pub struct Io { From 3a9cf40de3b9c6ae8ddd139415d3812b791cec1a Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Mon, 28 Feb 2022 16:45:52 +0100 Subject: [PATCH 02/42] Implemented basic viewport support --- imgui-examples/examples/hello_world.rs | 4 +- imgui-examples/examples/support/mod.rs | 8 +- imgui-glium-renderer/src/lib.rs | 3 + imgui-winit-support/src/lib.rs | 134 +++++++- imgui/src/context.rs | 66 +++- imgui/src/internal.rs | 15 +- imgui/src/io.rs | 73 +---- imgui/src/lib.rs | 2 + imgui/src/platform_io.rs | 418 +++++++++++++++++++++++++ 9 files changed, 646 insertions(+), 77 deletions(-) create mode 100644 imgui/src/platform_io.rs diff --git a/imgui-examples/examples/hello_world.rs b/imgui-examples/examples/hello_world.rs index 29f74ed..4a70e86 100644 --- a/imgui-examples/examples/hello_world.rs +++ b/imgui-examples/examples/hello_world.rs @@ -3,7 +3,9 @@ use imgui::*; mod support; fn main() { - let system = support::init(file!()); + let mut system = support::init(file!()); + system.enable_viewports(); + let mut value = 0; let choices = ["test test this is 1", "test test this is 2"]; system.main_loop(move |_, ui| { diff --git a/imgui-examples/examples/support/mod.rs b/imgui-examples/examples/support/mod.rs index 44e8825..52c4bcd 100644 --- a/imgui-examples/examples/support/mod.rs +++ b/imgui-examples/examples/support/mod.rs @@ -3,10 +3,11 @@ use glium::glutin::event::{Event, WindowEvent}; use glium::glutin::event_loop::{ControlFlow, EventLoop}; use glium::glutin::window::WindowBuilder; use glium::{Display, Surface}; -use imgui::{Context, FontConfig, FontGlyphRanges, FontSource, Ui}; +use imgui::{Context, FontConfig, FontGlyphRanges, FontSource, Ui, ConfigFlags}; use imgui_glium_renderer::Renderer; use imgui_winit_support::{HiDpiMode, WinitPlatform}; use std::path::Path; +use std::rc::Rc; use std::time::Instant; mod clipboard; @@ -112,6 +113,11 @@ pub fn init(title: &str) -> System { } impl System { + pub fn enable_viewports(&mut self) { + WinitPlatform::init_viewports(&mut self.imgui, &self.event_loop, self.display.gl_window().window()); + self.imgui.io_mut().config_flags.insert(ConfigFlags::VIEWPORTS_ENABLE); + } + pub fn main_loop(self, mut run_ui: F) { let System { event_loop, diff --git a/imgui-glium-renderer/src/lib.rs b/imgui-glium-renderer/src/lib.rs index eddc659..b1ea68b 100644 --- a/imgui-glium-renderer/src/lib.rs +++ b/imgui-glium-renderer/src/lib.rs @@ -150,6 +150,9 @@ impl Renderer { ctx.io_mut() .backend_flags .insert(BackendFlags::RENDERER_HAS_VTX_OFFSET); + ctx.io_mut() + .backend_flags + .insert(BackendFlags::RENDERER_HAS_VIEWPORTS); Ok(Renderer { ctx: Rc::clone(facade.get_context()), program, diff --git a/imgui-winit-support/src/lib.rs b/imgui-winit-support/src/lib.rs index 3c2c65d..0b79529 100644 --- a/imgui-winit-support/src/lib.rs +++ b/imgui-winit-support/src/lib.rs @@ -188,8 +188,8 @@ use winit_20 as winit; ))] use winit_19 as winit; -use imgui::{self, BackendFlags, ConfigFlags, Context, Io, Key, Ui}; -use std::cell::Cell; +use imgui::{self, BackendFlags, ConfigFlags, Context, Io, Key, Ui, PlatformViewportBackend, ViewportFlags, PlatformMonitor, Viewport}; +use std::{cell::Cell, rc::Rc}; use std::cmp::Ordering; use winit::dpi::{LogicalPosition, LogicalSize}; @@ -444,6 +444,110 @@ impl HiDpiMode { } } +struct ViewportBackend { + event_loop: *const winit::event_loop::EventLoopWindowTarget<()>, +} + +enum PlatformHandle { + MainWindow(*const winit::window::Window), + SecondaryWindow(winit::window::Window), +} + +impl PlatformHandle { + fn get(&self) -> &winit::window::Window { + match self { + PlatformHandle::MainWindow(ptr) => unsafe { &**ptr }, + PlatformHandle::SecondaryWindow(wnd) => wnd, + } + } +} + +impl PlatformViewportBackend for ViewportBackend { + fn create_window(&mut self, viewport: &mut imgui::Viewport) { + let window = winit::window::WindowBuilder::new() + .with_always_on_top(viewport.flags.contains(ViewportFlags::TOP_MOST)) + .with_decorations(!viewport.flags.contains(ViewportFlags::NO_DECORATION)) + .with_resizable(true) + .with_visible(false) + .build(unsafe{&*self.event_loop}) + .unwrap(); + + viewport.platform_handle = Box::into_raw(Box::new(PlatformHandle::SecondaryWindow(window))) as *mut _; + } + + fn destroy_window(&mut self, viewport: &mut imgui::Viewport) { + unsafe { + // drop window + Box::from_raw(viewport.platform_handle as *mut PlatformHandle); + } + } + + fn show_window(&mut self, viewport: &mut imgui::Viewport) { + let window = unsafe { (*(viewport.platform_handle as *const PlatformHandle)).get() }; + window.set_visible(true); + } + + fn set_window_pos(&mut self, viewport: &mut imgui::Viewport, pos: [f32; 2]) { + let window = unsafe { (*(viewport.platform_handle as *const PlatformHandle)).get() }; + window.set_outer_position(winit::dpi::LogicalPosition::new(pos[0], pos[1])); + } + + fn get_window_pos(&mut self, viewport: &mut imgui::Viewport) -> [f32; 2] { + let window = unsafe { (*(viewport.platform_handle as *const PlatformHandle)).get() }; + let pos = window.outer_position().unwrap(); + [pos.x as f32, pos.y as f32] + } + + fn set_window_size(&mut self, viewport: &mut imgui::Viewport, size: [f32; 2]) { + let window = unsafe { (*(viewport.platform_handle as *const PlatformHandle)).get() }; + window.set_inner_size(winit::dpi::LogicalSize::new(size[0], size[1])); + } + + fn get_window_size(&mut self, viewport: &mut imgui::Viewport) -> [f32; 2] { + let window = unsafe { (*(viewport.platform_handle as *const PlatformHandle)).get() }; + let size = window.inner_size(); + [size.width as f32, size.width as f32] + } + + fn set_window_focus(&mut self, viewport: &mut imgui::Viewport) { + let window = unsafe { (*(viewport.platform_handle as *const PlatformHandle)).get() }; + window.focus_window(); + } + + fn get_window_focus(&mut self, viewport: &mut imgui::Viewport) -> bool { + true + } + + fn get_window_minimized(&mut self, viewport: &mut imgui::Viewport) -> bool { + false + } + + fn set_window_title(&mut self, viewport: &mut imgui::Viewport, title: &str) { + let window = unsafe { (*(viewport.platform_handle as *const PlatformHandle)).get() }; + window.set_title(title); + } + + fn set_window_alpha(&mut self, viewport: &mut imgui::Viewport, alpha: f32) { + + } + + fn update_window(&mut self, viewport: &mut imgui::Viewport) { + + } + + fn render_window(&mut self, viewport: &mut imgui::Viewport) { + + } + + fn swap_buffers(&mut self, viewport: &mut imgui::Viewport) { + + } + + fn create_vk_surface(&mut self, viewport: &mut imgui::Viewport, instance: u64, out_surface: &mut u64) -> i32 { + 0 + } +} + impl WinitPlatform { /// Initializes a winit platform instance and configures imgui. /// @@ -491,6 +595,32 @@ impl WinitPlatform { mouse_buttons: [Button::INIT; 5], } } + + pub fn init_viewports(imgui: &mut Context, event_loop: &winit::event_loop::EventLoopWindowTarget<()>, main_window: &winit::window::Window) { + let io = imgui.io_mut(); + io.backend_flags.insert(BackendFlags::PLATFORM_HAS_VIEWPORTS); + + imgui.set_platform_backend(ViewportBackend{ + event_loop: event_loop as *const _, + }); + + let pio = imgui.platform_io_mut(); + let mut monitors = Vec::new(); + for monitor in main_window.available_monitors() { + monitors.push(PlatformMonitor { + main_pos: [monitor.position().x as f32, monitor.position().y as f32], + main_size: [monitor.size().width as f32, monitor.size().height as f32], + work_pos: [monitor.position().x as f32, monitor.position().y as f32], + work_size: [monitor.size().width as f32, monitor.size().height as f32], + dpi_scale: 1.0, + }); + } + pio.monitors.replace_from_slice(&monitors); + + let main_viewport = imgui.main_viewport_mut(); + main_viewport.platform_handle = Box::into_raw(Box::new(PlatformHandle::MainWindow(main_window as *const _))) as *mut _; + } + /// Attaches the platform instance to a winit window. /// /// This function configures imgui-rs in the following ways: diff --git a/imgui/src/context.rs b/imgui/src/context.rs index 8964f56..93ea312 100644 --- a/imgui/src/context.rs +++ b/imgui/src/context.rs @@ -9,7 +9,7 @@ use crate::clipboard::{ClipboardBackend, ClipboardContext}; use crate::fonts::atlas::{FontAtlas, FontId, SharedFontAtlas}; use crate::io::Io; use crate::style::Style; -use crate::{sys, DrawData, PlatformIo}; +use crate::{sys, DrawData, PlatformIo, PlatformViewportContext, RendererViewportContext, PlatformViewportBackend, RendererViewportBackend, Viewport}; use crate::{MouseCursor, Ui}; /// An imgui-rs context. @@ -60,6 +60,9 @@ pub struct Context { // imgui a mutable pointer to it. clipboard_ctx: Box>, + platform_viewport_ctx: Box>, + renderer_viewport_ctx: Box>, + ui: Ui, } @@ -216,6 +219,51 @@ impl Context { io.clipboard_user_data = clipboard_ctx.get() as *mut _; self.clipboard_ctx = clipboard_ctx; } + pub fn set_platform_backend(&mut self, backend: T) { + let ctx = Box::new(UnsafeCell::new(PlatformViewportContext { + backend: Box::new(backend), + })); + + let io = self.io_mut(); + io.backend_platform_user_data = ctx.get() as *mut _; + + let pio = self.platform_io_mut(); + pio.platform_create_window = Some(crate::platform_io::platform_create_window); + pio.platform_destroy_window = Some(crate::platform_io::platform_destroy_window); + pio.platform_show_window = Some(crate::platform_io::platform_show_window); + pio.platform_set_window_pos = Some(crate::platform_io::platform_set_window_pos); + pio.platform_get_window_pos = Some(crate::platform_io::platform_get_window_pos); + pio.platform_set_window_size = Some(crate::platform_io::platform_set_window_size); + pio.platform_get_window_size = Some(crate::platform_io::platform_get_window_size); + pio.platform_set_window_focus = Some(crate::platform_io::platform_set_window_focus); + pio.platform_get_window_focus = Some(crate::platform_io::platform_get_window_focus); + pio.platform_get_window_minimized = Some(crate::platform_io::platform_get_window_minimized); + pio.platform_set_window_title = Some(crate::platform_io::platform_set_window_title); + pio.platform_set_window_alpha = Some(crate::platform_io::platform_set_window_alpha); + pio.platform_update_window = Some(crate::platform_io::platform_update_window); + pio.platform_render_window = Some(crate::platform_io::platform_render_window); + pio.platform_swap_buffers = Some(crate::platform_io::platform_swap_buffers); + pio.platform_create_vk_surface = Some(crate::platform_io::platform_create_vk_surface); + + self.platform_viewport_ctx = ctx; + } + pub fn set_renderer_backend(&mut self, backend: T) { + let ctx = Box::new(UnsafeCell::new(RendererViewportContext { + backend: Box::new(backend), + })); + + let io = self.io_mut(); + io.backend_renderer_user_data = ctx.get() as *mut _; + + let pio = self.platform_io_mut(); + pio.renderer_create_window = Some(crate::platform_io::renderer_create_window); + pio.renderer_destroy_window = Some(crate::platform_io::renderer_destroy_window); + pio.renderer_set_window_size = Some(crate::platform_io::renderer_set_window_size); + pio.renderer_render_window = Some(crate::platform_io::renderer_render_window); + pio.renderer_swap_buffers = Some(crate::platform_io::renderer_swap_buffers); + + self.renderer_viewport_ctx = ctx; + } fn create_internal(mut shared_font_atlas: Option) -> Self { let _guard = CTX_MUTEX.lock(); assert!( @@ -239,6 +287,8 @@ impl Context { platform_name: None, renderer_name: None, clipboard_ctx: Box::new(ClipboardContext::dummy().into()), + platform_viewport_ctx: Box::new(UnsafeCell::new(PlatformViewportContext::dummy())), + renderer_viewport_ctx: Box::new(UnsafeCell::new(RendererViewportContext::dummy())), ui: Ui { buffer: UnsafeCell::new(crate::string::UiBuffer::new(1024)), }, @@ -328,6 +378,8 @@ impl SuspendedContext { platform_name: None, renderer_name: None, clipboard_ctx: Box::new(ClipboardContext::dummy().into()), + platform_viewport_ctx: Box::new(UnsafeCell::new(PlatformViewportContext::dummy())), + renderer_viewport_ctx: Box::new(UnsafeCell::new(RendererViewportContext::dummy())), ui: Ui { buffer: UnsafeCell::new(crate::string::UiBuffer::new(1024)), }, @@ -485,12 +537,22 @@ impl Context { &*(sys::igGetPlatformIO() as *const PlatformIo) } } - pub fn platform_io_mut(&mut self) -> &PlatformIo { + pub fn platform_io_mut(&mut self) -> &mut PlatformIo { unsafe { // safe because PlatformIo is a transparent wrapper around sys::ImGuiPlatformIO &mut *(sys::igGetPlatformIO() as *mut PlatformIo) } } + pub fn main_viewport(&self) -> &Viewport { + unsafe { + &*(sys::igGetMainViewport() as *mut Viewport) + } + } + pub fn main_viewport_mut(&mut self) -> &mut Viewport { + unsafe { + &mut *(sys::igGetMainViewport() as *mut Viewport) + } + } /// Returns an immutable reference to the user interface style #[doc(alias = "GetStyle")] pub fn style(&self) -> &Style { diff --git a/imgui/src/internal.rs b/imgui/src/internal.rs index 0af90a1..af24cca 100644 --- a/imgui/src/internal.rs +++ b/imgui/src/internal.rs @@ -1,6 +1,6 @@ //! Internal raw utilities (don't use unless you know what you're doing!) -use std::slice; +use std::{slice, mem::size_of}; /// A generic version of the raw imgui-sys ImVector struct types #[repr(C)] @@ -15,6 +15,19 @@ impl ImVector { pub fn as_slice(&self) -> &[T] { unsafe { slice::from_raw_parts(self.data, self.size as usize) } } + + pub fn replace_from_slice(&mut self, data: &[T]) { + unsafe { + sys::igMemFree(self.data as *mut _); + + let buffer_ptr = sys::igMemAlloc(size_of::() * data.len()) as *mut T; + buffer_ptr.copy_from_nonoverlapping(data.as_ptr(), data.len()); + + self.size = data.len() as i32; + self.capacity = data.len() as i32; + self.data = buffer_ptr; + } + } } #[test] diff --git a/imgui/src/io.rs b/imgui/src/io.rs index d4c4e92..7681ed8 100644 --- a/imgui/src/io.rs +++ b/imgui/src/io.rs @@ -1,7 +1,7 @@ use bitflags::bitflags; use std::f32; use std::ops::{Index, IndexMut}; -use std::os::raw::{c_char, c_void, c_int}; +use std::os::raw::{c_char, c_void}; use std::time::Duration; use crate::fonts::atlas::FontAtlas; @@ -158,73 +158,6 @@ fn test_nav_input_variants() { } } -#[cfg(feature = "docking")] -#[repr(C)] -pub struct PlatformIo { - pub(crate) platform_create_window: Option, - pub(crate) platform_destroy_window: Option, - pub(crate) platform_show_window: Option, - pub(crate) platform_set_window_pos: Option, - pub(crate) platform_get_window_pos: Option sys::ImVec2>, - pub(crate) platform_set_window_size: Option, - pub(crate) platform_get_window_size: Option sys::ImVec2>, - pub(crate) platform_set_window_focus: Option, - pub(crate) platform_get_window_focus: Option bool>, - pub(crate) platform_get_window_minimized: Option bool>, - pub(crate) platform_set_window_title: Option, - pub(crate) platform_set_window_alpha: Option, - pub(crate) platform_update_window: Option, - pub(crate) platform_render_window: Option, - pub(crate) platform_swap_buffers: Option, - pub(crate) platform_get_window_dpi_scale: Option f32>, - pub(crate) platform_on_changed_viewport: Option, - pub(crate) platform_create_vk_surface: Option c_int>, - - pub(crate) renderer_create_window: Option, - pub(crate) renderer_destroy_window: Option, - pub(crate) renderer_set_window_size: Option, - pub(crate) renderer_render_window: Option, - pub(crate) renderer_swap_buffers: Option, - - pub(crate) monitors: ImVector, - - pub(crate) viewports: ImVector<*mut Viewport>, -} - -unsafe impl RawCast for PlatformIo {} - -#[cfg(feature = "docking")] -#[repr(C)] -pub struct Viewport { - pub(crate) id: crate::Id, - pub(crate) flags: ViewportFlags, - pub(crate) pos: [f32; 2], - pub(crate) size: [f32; 2], - pub(crate) work_pos: [f32; 2], - pub(crate) work_size: [f32; 2], - pub(crate) dpi_scale: f32, - pub(crate) parent_viewport_id: crate::Id, - pub(crate) draw_data: *mut crate::DrawData, - - pub(crate) renderer_user_data: *mut c_void, - pub(crate) platform_user_data: *mut c_void, - pub(crate) platform_handle: *mut c_void, - pub(crate) platform_handle_raw: *mut c_void, - pub(crate) platform_request_move: bool, - pub(crate) platform_request_resize: bool, - pub(crate) platform_request_close: bool, -} - -#[cfg(feature = "docking")] -#[repr(C)] -pub struct PlatformMonitor { - main_pos: [f32; 2], - main_size: [f32; 2], - work_pos: [f32; 2], - work_size: [f32; 2], - dpi_scale: f32, -} - /// Settings and inputs/outputs for imgui-rs #[repr(C)] pub struct Io { @@ -320,8 +253,8 @@ pub struct Io { pub(crate) backend_platform_name: *const c_char, pub(crate) backend_renderer_name: *const c_char, - backend_platform_user_data: *mut c_void, - backend_renderer_user_data: *mut c_void, + pub(crate) backend_platform_user_data: *mut c_void, + pub(crate) backend_renderer_user_data: *mut c_void, backend_language_user_data: *mut c_void, pub(crate) get_clipboard_text_fn: Option *const c_char>, diff --git a/imgui/src/lib.rs b/imgui/src/lib.rs index 7eb289f..b80a2ca 100644 --- a/imgui/src/lib.rs +++ b/imgui/src/lib.rs @@ -20,6 +20,7 @@ pub use self::input::keyboard::*; pub use self::input::mouse::*; pub use self::input_widget::*; pub use self::io::*; +pub use self::platform_io::*; pub use self::layout::*; pub use self::list_clipper::ListClipper; pub use self::plothistogram::PlotHistogram; @@ -68,6 +69,7 @@ mod input; mod input_widget; pub mod internal; mod io; +mod platform_io; mod layout; mod list_clipper; mod math; diff --git a/imgui/src/platform_io.rs b/imgui/src/platform_io.rs new file mode 100644 index 0000000..79a7d78 --- /dev/null +++ b/imgui/src/platform_io.rs @@ -0,0 +1,418 @@ +use std::{os::raw::{c_char, c_int}, ffi::{c_void, CStr}}; + +use crate::{internal::{ImVector, RawCast}, ViewportFlags}; + +#[cfg(feature = "docking")] +#[repr(C)] +pub struct PlatformIo { + pub(crate) platform_create_window: Option, + pub(crate) platform_destroy_window: Option, + pub(crate) platform_show_window: Option, + pub(crate) platform_set_window_pos: Option, + pub(crate) platform_get_window_pos: Option sys::ImVec2>, + pub(crate) platform_set_window_size: Option, + pub(crate) platform_get_window_size: Option sys::ImVec2>, + pub(crate) platform_set_window_focus: Option, + pub(crate) platform_get_window_focus: Option bool>, + pub(crate) platform_get_window_minimized: Option bool>, + pub(crate) platform_set_window_title: Option, + pub(crate) platform_set_window_alpha: Option, + pub(crate) platform_update_window: Option, + pub(crate) platform_render_window: Option, + pub(crate) platform_swap_buffers: Option, + pub(crate) platform_get_window_dpi_scale: Option f32>, + pub(crate) platform_on_changed_viewport: Option, + pub(crate) platform_set_ime_input_pos: Option, + pub(crate) platform_create_vk_surface: Option c_int>, + + pub(crate) renderer_create_window: Option, + pub(crate) renderer_destroy_window: Option, + pub(crate) renderer_set_window_size: Option, + pub(crate) renderer_render_window: Option, + pub(crate) renderer_swap_buffers: Option, + + pub monitors: ImVector, + + pub(crate) viewports: ImVector<*mut Viewport>, +} + +unsafe impl RawCast for PlatformIo {} + +#[test] +#[cfg(test)] +fn test_platform_io_memory_layout() { + use std::mem; + assert_eq!(mem::size_of::(), mem::size_of::()); + assert_eq!(mem::align_of::(), mem::align_of::()); + use sys::ImGuiPlatformIO; + macro_rules! assert_field_offset { + ($l:ident, $r:ident) => { + assert_eq!( + memoffset::offset_of!(PlatformIo, $l), + memoffset::offset_of!(ImGuiPlatformIO, $r) + ); + }; + } + + assert_field_offset!(platform_create_window, Platform_CreateWindow); + assert_field_offset!(platform_destroy_window, Platform_DestroyWindow); + assert_field_offset!(platform_show_window, Platform_ShowWindow); + assert_field_offset!(platform_set_window_pos, Platform_SetWindowPos); + assert_field_offset!(platform_get_window_pos, Platform_GetWindowPos); + assert_field_offset!(platform_set_window_size, Platform_SetWindowSize); + assert_field_offset!(platform_get_window_size, Platform_GetWindowSize); + assert_field_offset!(platform_set_window_focus, Platform_SetWindowFocus); + assert_field_offset!(platform_get_window_focus, Platform_GetWindowFocus); + assert_field_offset!(platform_get_window_minimized, Platform_GetWindowMinimized); + assert_field_offset!(platform_set_window_title, Platform_SetWindowTitle); + assert_field_offset!(platform_set_window_alpha, Platform_SetWindowAlpha); + assert_field_offset!(platform_update_window, Platform_UpdateWindow); + assert_field_offset!(platform_render_window, Platform_RenderWindow); + assert_field_offset!(platform_swap_buffers, Platform_SwapBuffers); + assert_field_offset!(platform_get_window_dpi_scale, Platform_GetWindowDpiScale); + assert_field_offset!(platform_on_changed_viewport, Platform_OnChangedViewport); + assert_field_offset!(platform_set_ime_input_pos, Platform_SetImeInputPos); + assert_field_offset!(platform_create_vk_surface, Platform_CreateVkSurface); + + assert_field_offset!(renderer_create_window, Renderer_CreateWindow); + assert_field_offset!(renderer_destroy_window, Renderer_DestroyWindow); + assert_field_offset!(renderer_set_window_size, Renderer_SetWindowSize); + assert_field_offset!(renderer_render_window, Renderer_RenderWindow); + assert_field_offset!(renderer_swap_buffers, Renderer_SwapBuffers); + + assert_field_offset!(monitors, Monitors); + assert_field_offset!(viewports, Viewports); +} + +pub trait PlatformViewportBackend: 'static { + fn create_window(&mut self, viewport: &mut Viewport); + fn destroy_window(&mut self, viewport: &mut Viewport); + fn show_window(&mut self, viewport: &mut Viewport); + fn set_window_pos(&mut self, viewport: &mut Viewport, pos: [f32; 2]); + fn get_window_pos(&mut self, viewport: &mut Viewport) -> [f32; 2]; + fn set_window_size(&mut self, viewport: &mut Viewport, size: [f32; 2]); + fn get_window_size(&mut self, viewport: &mut Viewport) -> [f32; 2]; + fn set_window_focus(&mut self, viewport: &mut Viewport); + fn get_window_focus(&mut self, viewport: &mut Viewport) -> bool; + fn get_window_minimized(&mut self, viewport: &mut Viewport) -> bool; + fn set_window_title(&mut self, viewport: &mut Viewport, title: &str); + fn set_window_alpha(&mut self, viewport: &mut Viewport, alpha: f32); + + fn update_window(&mut self, viewport: &mut Viewport); + fn render_window(&mut self, viewport: &mut Viewport); + fn swap_buffers(&mut self, viewport: &mut Viewport); + fn create_vk_surface(&mut self, viewport: &mut Viewport, instance: u64, out_surface: &mut u64) -> i32; +} + +fn get_platform_ctx() -> &'static mut PlatformViewportContext { + unsafe { + &mut *((*sys::igGetIO()).BackendPlatformUserData as *mut PlatformViewportContext) + } +} + +fn get_renderer_ctx() -> &'static mut RendererViewportContext { + unsafe { + &mut *((*sys::igGetIO()).BackendRendererUserData as *mut RendererViewportContext) + } +} + +pub(crate) extern "C" fn platform_create_window(viewport: *mut Viewport) { + let ctx = get_platform_ctx(); + ctx.backend.create_window(unsafe{&mut *viewport}); +} +pub(crate) extern "C" fn platform_destroy_window(viewport: *mut Viewport) { + let ctx = get_platform_ctx(); + ctx.backend.destroy_window(unsafe{&mut *viewport}); +} +pub(crate) extern "C" fn platform_show_window(viewport: *mut Viewport) { + let ctx = get_platform_ctx(); + ctx.backend.show_window(unsafe{&mut *viewport}); +} +pub(crate) extern "C" fn platform_set_window_pos(viewport: *mut Viewport, pos: sys::ImVec2) { + let ctx = get_platform_ctx(); + ctx.backend.set_window_pos(unsafe{&mut *viewport}, [pos.x, pos.y]); +} +pub(crate) extern "C" fn platform_get_window_pos(viewport: *mut Viewport) -> sys::ImVec2 { + let ctx = get_platform_ctx(); + let pos = ctx.backend.get_window_pos(unsafe{&mut *viewport}); + sys::ImVec2::new(pos[0], pos[1]) +} +pub(crate) extern "C" fn platform_set_window_size(viewport: *mut Viewport, size: sys::ImVec2) { + let ctx = get_platform_ctx(); + ctx.backend.set_window_size(unsafe{&mut *viewport}, [size.x, size.y]); +} +pub(crate) extern "C" fn platform_get_window_size(viewport: *mut Viewport) -> sys::ImVec2 { + let ctx = get_platform_ctx(); + let size = ctx.backend.get_window_size(unsafe{&mut *viewport}); + sys::ImVec2::new(size[0], size[1]) +} +pub(crate) extern "C" fn platform_set_window_focus(viewport: *mut Viewport) { + let ctx = get_platform_ctx(); + ctx.backend.set_window_focus(unsafe{&mut *viewport}); +} +pub(crate) extern "C" fn platform_get_window_focus(viewport: *mut Viewport) -> bool { + let ctx = get_platform_ctx(); + ctx.backend.get_window_focus(unsafe{&mut *viewport}) +} +pub(crate) extern "C" fn platform_get_window_minimized(viewport: *mut Viewport) -> bool { + let ctx = get_platform_ctx(); + ctx.backend.get_window_minimized(unsafe{&mut *viewport}) +} +pub(crate) extern "C" fn platform_set_window_title(viewport: *mut Viewport, title: *const c_char) { + let ctx = get_platform_ctx(); + let title = unsafe { CStr::from_ptr(title).to_str().unwrap() }; + ctx.backend.set_window_title(unsafe{&mut *viewport}, title); +} +pub(crate) extern "C" fn platform_set_window_alpha(viewport: *mut Viewport, alpha: f32) { + let ctx = get_platform_ctx(); + ctx.backend.set_window_alpha(unsafe{&mut *viewport}, alpha); +} +pub(crate) extern "C" fn platform_update_window(viewport: *mut Viewport) { + let ctx = get_platform_ctx(); + ctx.backend.update_window(unsafe{&mut *viewport}); +} +pub(crate) extern "C" fn platform_render_window(viewport: *mut Viewport, _arg: *mut c_void) { + let ctx = get_platform_ctx(); + ctx.backend.render_window(unsafe{&mut *viewport}); +} +pub(crate) extern "C" fn platform_swap_buffers(viewport: *mut Viewport, _arg: *mut c_void) { + let ctx = get_platform_ctx(); + ctx.backend.swap_buffers(unsafe{&mut *viewport}); +} +pub(crate) extern "C" fn platform_create_vk_surface(viewport: *mut Viewport, instance: u64, _arg: *const c_void, out_surface: *mut u64) -> c_int { + let ctx = get_platform_ctx(); + ctx.backend.create_vk_surface(unsafe{&mut *viewport}, instance, unsafe{&mut *out_surface}) +} + +pub(crate) struct DummyPlatformViewportBackend {} +impl PlatformViewportBackend for DummyPlatformViewportBackend { + fn create_window(&mut self, viewport: &mut Viewport) { + unimplemented!() + } + + fn destroy_window(&mut self, viewport: &mut Viewport) { + unimplemented!() + } + + fn show_window(&mut self, viewport: &mut Viewport) { + unimplemented!() + } + + fn set_window_pos(&mut self, viewport: &mut Viewport, pos: [f32; 2]) { + unimplemented!() + } + + fn get_window_pos(&mut self, viewport: &mut Viewport) -> [f32; 2] { + unimplemented!() + } + + fn set_window_size(&mut self, viewport: &mut Viewport, size: [f32; 2]) { + unimplemented!() + } + + fn get_window_size(&mut self, viewport: &mut Viewport) -> [f32; 2] { + unimplemented!() + } + + fn set_window_focus(&mut self, viewport: &mut Viewport) { + unimplemented!() + } + + fn get_window_focus(&mut self, viewport: &mut Viewport) -> bool { + unimplemented!() + } + + fn get_window_minimized(&mut self, viewport: &mut Viewport) -> bool { + unimplemented!() + } + + fn set_window_title(&mut self, viewport: &mut Viewport, title: &str) { + unimplemented!() + } + + fn set_window_alpha(&mut self, viewport: &mut Viewport, alpha: f32) { + unimplemented!() + } + + fn update_window(&mut self, viewport: &mut Viewport) { + unimplemented!() + } + + fn render_window(&mut self, viewport: &mut Viewport) { + unimplemented!() + } + + fn swap_buffers(&mut self, viewport: &mut Viewport) { + unimplemented!() + } + + fn create_vk_surface(&mut self, viewport: &mut Viewport, instance: u64, out_surface: &mut u64) -> i32 { + unimplemented!() + } +} + +pub(crate) struct PlatformViewportContext { + pub(crate) backend: Box, +} + +impl PlatformViewportContext { + pub(crate) fn dummy() -> Self { + Self { + backend: Box::new(DummyPlatformViewportBackend{}), + } + } +} + +pub trait RendererViewportBackend: 'static { + fn create_window(&mut self, viewport: &mut Viewport); + fn destroy_window(&mut self, viewport: &mut Viewport); + fn set_window_size(&mut self, viewport: &mut Viewport, size: [f32; 2]); + fn render_window(&mut self, viewport: &mut Viewport); + fn swap_buffers(&mut self, viewport: &mut Viewport); +} + +pub(crate) extern "C" fn renderer_create_window(viewport: *mut Viewport) { + let ctx = get_renderer_ctx(); + ctx.backend.create_window(unsafe{&mut *viewport}); +} +pub(crate) extern "C" fn renderer_destroy_window(viewport: *mut Viewport) { + let ctx = get_renderer_ctx(); + ctx.backend.destroy_window(unsafe{&mut *viewport}); +} +pub(crate) extern "C" fn renderer_set_window_size(viewport: *mut Viewport, size: sys::ImVec2) { + let ctx = get_renderer_ctx(); + ctx.backend.set_window_size(unsafe{&mut *viewport}, [size.x, size.y]); +} +pub(crate) extern "C" fn renderer_render_window(viewport: *mut Viewport, _arg: *mut c_void) { + let ctx = get_renderer_ctx(); + ctx.backend.render_window(unsafe{&mut *viewport}); +} +pub(crate) extern "C" fn renderer_swap_buffers(viewport: *mut Viewport, _arg: *mut c_void) { + let ctx = get_renderer_ctx(); + ctx.backend.swap_buffers(unsafe{&mut *viewport}); +} + +pub(crate) struct DummyRendererViewportBackend {} +impl RendererViewportBackend for DummyRendererViewportBackend { + fn create_window(&mut self, viewport: &mut Viewport) { + unimplemented!() + } + + fn destroy_window(&mut self, viewport: &mut Viewport) { + unimplemented!() + } + + fn set_window_size(&mut self, viewport: &mut Viewport, size: [f32; 2]) { + unimplemented!() + } + + fn render_window(&mut self, viewport: &mut Viewport) { + unimplemented!() + } + + fn swap_buffers(&mut self, viewport: &mut Viewport) { + unimplemented!() + } +} + +pub(crate) struct RendererViewportContext { + pub(crate) backend: Box, +} + +impl RendererViewportContext { + pub(crate) fn dummy() -> Self { + Self { + backend: Box::new(DummyRendererViewportBackend{}), + } + } +} + +#[cfg(feature = "docking")] +#[repr(C)] +pub struct Viewport { + pub(crate) id: crate::Id, + pub flags: ViewportFlags, + pub(crate) pos: [f32; 2], + pub(crate) size: [f32; 2], + pub(crate) work_pos: [f32; 2], + pub(crate) work_size: [f32; 2], + pub(crate) dpi_scale: f32, + pub(crate) parent_viewport_id: crate::Id, + pub(crate) draw_data: *mut crate::DrawData, + + pub renderer_user_data: *mut c_void, + pub platform_user_data: *mut c_void, + pub platform_handle: *mut c_void, + pub platform_handle_raw: *mut c_void, + pub platform_request_move: bool, + pub platform_request_resize: bool, + pub platform_request_close: bool, +} + +#[test] +#[cfg(test)] +fn test_viewport_memory_layout() { + use std::mem; + assert_eq!(mem::size_of::(), mem::size_of::()); + assert_eq!(mem::align_of::(), mem::align_of::()); + use sys::ImGuiViewport; + macro_rules! assert_field_offset { + ($l:ident, $r:ident) => { + assert_eq!( + memoffset::offset_of!(Viewport, $l), + memoffset::offset_of!(ImGuiViewport, $r) + ); + }; + } + + assert_field_offset!(id, ID); + assert_field_offset!(flags, Flags); + assert_field_offset!(pos, Pos); + assert_field_offset!(size, Size); + assert_field_offset!(work_pos, WorkPos); + assert_field_offset!(work_size, WorkSize); + assert_field_offset!(dpi_scale, DpiScale); + assert_field_offset!(parent_viewport_id, ParentViewportId); + assert_field_offset!(draw_data, DrawData); + + assert_field_offset!(renderer_user_data, RendererUserData); + assert_field_offset!(platform_user_data, PlatformUserData); + assert_field_offset!(platform_handle, PlatformHandle); + assert_field_offset!(platform_handle_raw, PlatformHandleRaw); + assert_field_offset!(platform_request_move, PlatformRequestMove); + assert_field_offset!(platform_request_resize, PlatformRequestResize); + assert_field_offset!(platform_request_close, PlatformRequestClose); +} + +#[cfg(feature = "docking")] +#[repr(C)] +pub struct PlatformMonitor { + pub main_pos: [f32; 2], + pub main_size: [f32; 2], + pub work_pos: [f32; 2], + pub work_size: [f32; 2], + pub dpi_scale: f32, +} + +#[test] +#[cfg(test)] +fn test_platform_monitor_memory_layout() { + use std::mem; + assert_eq!(mem::size_of::(), mem::size_of::()); + assert_eq!(mem::align_of::(), mem::align_of::()); + use sys::ImGuiPlatformMonitor; + macro_rules! assert_field_offset { + ($l:ident, $r:ident) => { + assert_eq!( + memoffset::offset_of!(PlatformMonitor, $l), + memoffset::offset_of!(ImGuiPlatformMonitor, $r) + ); + }; + } + + assert_field_offset!(main_pos, MainPos); + assert_field_offset!(main_size, MainSize); + assert_field_offset!(work_pos, WorkPos); + assert_field_offset!(work_size, WorkSize); + assert_field_offset!(dpi_scale, DpiScale); +} From 4d32d509627158a82fdb5dae686dfbf27aabbdec Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Mon, 28 Feb 2022 16:59:40 +0100 Subject: [PATCH 03/42] Fixed clippy --- imgui-examples/examples/support/mod.rs | 1 - imgui-winit-support/src/lib.rs | 18 +++++------ imgui/src/platform_io.rs | 42 +++++++++++++------------- 3 files changed, 30 insertions(+), 31 deletions(-) diff --git a/imgui-examples/examples/support/mod.rs b/imgui-examples/examples/support/mod.rs index 52c4bcd..ac41295 100644 --- a/imgui-examples/examples/support/mod.rs +++ b/imgui-examples/examples/support/mod.rs @@ -7,7 +7,6 @@ use imgui::{Context, FontConfig, FontGlyphRanges, FontSource, Ui, ConfigFlags}; use imgui_glium_renderer::Renderer; use imgui_winit_support::{HiDpiMode, WinitPlatform}; use std::path::Path; -use std::rc::Rc; use std::time::Instant; mod clipboard; diff --git a/imgui-winit-support/src/lib.rs b/imgui-winit-support/src/lib.rs index 0b79529..cb1a2d9 100644 --- a/imgui-winit-support/src/lib.rs +++ b/imgui-winit-support/src/lib.rs @@ -188,8 +188,8 @@ use winit_20 as winit; ))] use winit_19 as winit; -use imgui::{self, BackendFlags, ConfigFlags, Context, Io, Key, Ui, PlatformViewportBackend, ViewportFlags, PlatformMonitor, Viewport}; -use std::{cell::Cell, rc::Rc}; +use imgui::{self, BackendFlags, ConfigFlags, Context, Io, Key, Ui, PlatformViewportBackend, ViewportFlags, PlatformMonitor}; +use std::cell::Cell; use std::cmp::Ordering; use winit::dpi::{LogicalPosition, LogicalSize}; @@ -514,11 +514,11 @@ impl PlatformViewportBackend for ViewportBackend { window.focus_window(); } - fn get_window_focus(&mut self, viewport: &mut imgui::Viewport) -> bool { + fn get_window_focus(&mut self, _viewport: &mut imgui::Viewport) -> bool { true } - fn get_window_minimized(&mut self, viewport: &mut imgui::Viewport) -> bool { + fn get_window_minimized(&mut self, _viewport: &mut imgui::Viewport) -> bool { false } @@ -527,23 +527,23 @@ impl PlatformViewportBackend for ViewportBackend { window.set_title(title); } - fn set_window_alpha(&mut self, viewport: &mut imgui::Viewport, alpha: f32) { + fn set_window_alpha(&mut self, _viewport: &mut imgui::Viewport, _alpha: f32) { } - fn update_window(&mut self, viewport: &mut imgui::Viewport) { + fn update_window(&mut self, _viewport: &mut imgui::Viewport) { } - fn render_window(&mut self, viewport: &mut imgui::Viewport) { + fn render_window(&mut self, _viewport: &mut imgui::Viewport) { } - fn swap_buffers(&mut self, viewport: &mut imgui::Viewport) { + fn swap_buffers(&mut self, _viewport: &mut imgui::Viewport) { } - fn create_vk_surface(&mut self, viewport: &mut imgui::Viewport, instance: u64, out_surface: &mut u64) -> i32 { + fn create_vk_surface(&mut self, _viewport: &mut imgui::Viewport, _instance: u64, _out_surface: &mut u64) -> i32 { 0 } } diff --git a/imgui/src/platform_io.rs b/imgui/src/platform_io.rs index 79a7d78..191251c 100644 --- a/imgui/src/platform_io.rs +++ b/imgui/src/platform_io.rs @@ -186,67 +186,67 @@ pub(crate) extern "C" fn platform_create_vk_surface(viewport: *mut Viewport, ins pub(crate) struct DummyPlatformViewportBackend {} impl PlatformViewportBackend for DummyPlatformViewportBackend { - fn create_window(&mut self, viewport: &mut Viewport) { + fn create_window(&mut self, _viewport: &mut Viewport) { unimplemented!() } - fn destroy_window(&mut self, viewport: &mut Viewport) { + fn destroy_window(&mut self, _viewport: &mut Viewport) { unimplemented!() } - fn show_window(&mut self, viewport: &mut Viewport) { + fn show_window(&mut self, _viewport: &mut Viewport) { unimplemented!() } - fn set_window_pos(&mut self, viewport: &mut Viewport, pos: [f32; 2]) { + fn set_window_pos(&mut self, _viewport: &mut Viewport, _pos: [f32; 2]) { unimplemented!() } - fn get_window_pos(&mut self, viewport: &mut Viewport) -> [f32; 2] { + fn get_window_pos(&mut self, _viewport: &mut Viewport) -> [f32; 2] { unimplemented!() } - fn set_window_size(&mut self, viewport: &mut Viewport, size: [f32; 2]) { + fn set_window_size(&mut self, _viewport: &mut Viewport, _size: [f32; 2]) { unimplemented!() } - fn get_window_size(&mut self, viewport: &mut Viewport) -> [f32; 2] { + fn get_window_size(&mut self, _viewport: &mut Viewport) -> [f32; 2] { unimplemented!() } - fn set_window_focus(&mut self, viewport: &mut Viewport) { + fn set_window_focus(&mut self, _viewport: &mut Viewport) { unimplemented!() } - fn get_window_focus(&mut self, viewport: &mut Viewport) -> bool { + fn get_window_focus(&mut self, _viewport: &mut Viewport) -> bool { unimplemented!() } - fn get_window_minimized(&mut self, viewport: &mut Viewport) -> bool { + fn get_window_minimized(&mut self, _viewport: &mut Viewport) -> bool { unimplemented!() } - fn set_window_title(&mut self, viewport: &mut Viewport, title: &str) { + fn set_window_title(&mut self, _viewport: &mut Viewport, _title: &str) { unimplemented!() } - fn set_window_alpha(&mut self, viewport: &mut Viewport, alpha: f32) { + fn set_window_alpha(&mut self, _viewport: &mut Viewport, _alpha: f32) { unimplemented!() } - fn update_window(&mut self, viewport: &mut Viewport) { + fn update_window(&mut self, _viewport: &mut Viewport) { unimplemented!() } - fn render_window(&mut self, viewport: &mut Viewport) { + fn render_window(&mut self, _viewport: &mut Viewport) { unimplemented!() } - fn swap_buffers(&mut self, viewport: &mut Viewport) { + fn swap_buffers(&mut self, _viewport: &mut Viewport) { unimplemented!() } - fn create_vk_surface(&mut self, viewport: &mut Viewport, instance: u64, out_surface: &mut u64) -> i32 { + fn create_vk_surface(&mut self, _viewport: &mut Viewport, _instance: u64, _out_surface: &mut u64) -> i32 { unimplemented!() } } @@ -294,23 +294,23 @@ pub(crate) extern "C" fn renderer_swap_buffers(viewport: *mut Viewport, _arg: *m pub(crate) struct DummyRendererViewportBackend {} impl RendererViewportBackend for DummyRendererViewportBackend { - fn create_window(&mut self, viewport: &mut Viewport) { + fn create_window(&mut self, _viewport: &mut Viewport) { unimplemented!() } - fn destroy_window(&mut self, viewport: &mut Viewport) { + fn destroy_window(&mut self, _viewport: &mut Viewport) { unimplemented!() } - fn set_window_size(&mut self, viewport: &mut Viewport, size: [f32; 2]) { + fn set_window_size(&mut self, _viewport: &mut Viewport, _size: [f32; 2]) { unimplemented!() } - fn render_window(&mut self, viewport: &mut Viewport) { + fn render_window(&mut self, _viewport: &mut Viewport) { unimplemented!() } - fn swap_buffers(&mut self, viewport: &mut Viewport) { + fn swap_buffers(&mut self, _viewport: &mut Viewport) { unimplemented!() } } From 1d7bcd33adb98a9ce8b9a970d53f9e406da92fb6 Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Tue, 1 Mar 2022 08:08:53 +0100 Subject: [PATCH 04/42] Fixed crashes --- imgui-examples/examples/support/mod.rs | 1 + imgui-winit-support/src/lib.rs | 4 +++- imgui/src/context.rs | 15 +++++++++++++-- imgui/src/internal.rs | 5 +++++ imgui/src/platform_io.rs | 23 ++++++++++++++++------- 5 files changed, 38 insertions(+), 10 deletions(-) diff --git a/imgui-examples/examples/support/mod.rs b/imgui-examples/examples/support/mod.rs index ac41295..546c4dc 100644 --- a/imgui-examples/examples/support/mod.rs +++ b/imgui-examples/examples/support/mod.rs @@ -158,6 +158,7 @@ impl System { renderer .render(&mut target, draw_data) .expect("Rendering failed"); + imgui.update_platform_windows(); target.finish().expect("Failed to swap buffers"); } Event::WindowEvent { diff --git a/imgui-winit-support/src/lib.rs b/imgui-winit-support/src/lib.rs index cb1a2d9..83dd78c 100644 --- a/imgui-winit-support/src/lib.rs +++ b/imgui-winit-support/src/lib.rs @@ -188,7 +188,7 @@ use winit_20 as winit; ))] use winit_19 as winit; -use imgui::{self, BackendFlags, ConfigFlags, Context, Io, Key, Ui, PlatformViewportBackend, ViewportFlags, PlatformMonitor}; +use imgui::{self, BackendFlags, ConfigFlags, Context, Io, Key, Ui, PlatformViewportBackend, ViewportFlags, PlatformMonitor, Viewport}; use std::cell::Cell; use std::cmp::Ordering; use winit::dpi::{LogicalPosition, LogicalSize}; @@ -619,6 +619,8 @@ impl WinitPlatform { let main_viewport = imgui.main_viewport_mut(); main_viewport.platform_handle = Box::into_raw(Box::new(PlatformHandle::MainWindow(main_window as *const _))) as *mut _; + println!("MAIN VIEWPORT: {:016X}", main_viewport as *mut Viewport as u64); + println!("PLATFORM HANDLE: {:016X}", main_viewport.platform_handle as u64); } /// Attaches the platform instance to a winit window. diff --git a/imgui/src/context.rs b/imgui/src/context.rs index 93ea312..a233795 100644 --- a/imgui/src/context.rs +++ b/imgui/src/context.rs @@ -232,9 +232,15 @@ impl Context { pio.platform_destroy_window = Some(crate::platform_io::platform_destroy_window); pio.platform_show_window = Some(crate::platform_io::platform_show_window); pio.platform_set_window_pos = Some(crate::platform_io::platform_set_window_pos); - pio.platform_get_window_pos = Some(crate::platform_io::platform_get_window_pos); + // pio.platform_get_window_pos = Some(crate::platform_io::platform_get_window_pos); + unsafe { + crate::platform_io::ImGuiPlatformIO_Set_Platform_GetWindowPos(pio, crate::platform_io::platform_get_window_pos); + } pio.platform_set_window_size = Some(crate::platform_io::platform_set_window_size); - pio.platform_get_window_size = Some(crate::platform_io::platform_get_window_size); + // pio.platform_get_window_size = Some(crate::platform_io::platform_get_window_size); + unsafe { + crate::platform_io::ImGuiPlatformIO_Set_Platform_GetWindowSize(pio, crate::platform_io::platform_get_window_size); + } pio.platform_set_window_focus = Some(crate::platform_io::platform_set_window_focus); pio.platform_get_window_focus = Some(crate::platform_io::platform_get_window_focus); pio.platform_get_window_minimized = Some(crate::platform_io::platform_get_window_minimized); @@ -264,6 +270,11 @@ impl Context { self.renderer_viewport_ctx = ctx; } + pub fn update_platform_windows(&mut self) { + unsafe { + sys::igUpdatePlatformWindows(); + } + } fn create_internal(mut shared_font_atlas: Option) -> Self { let _guard = CTX_MUTEX.lock(); assert!( diff --git a/imgui/src/internal.rs b/imgui/src/internal.rs index af24cca..d7869a3 100644 --- a/imgui/src/internal.rs +++ b/imgui/src/internal.rs @@ -16,6 +16,11 @@ impl ImVector { unsafe { slice::from_raw_parts(self.data, self.size as usize) } } + #[inline] + pub fn as_slice_mut(&mut self) -> &mut [T] { + unsafe { slice::from_raw_parts_mut(self.data, self.size as usize) } + } + pub fn replace_from_slice(&mut self, data: &[T]) { unsafe { sys::igMemFree(self.data as *mut _); diff --git a/imgui/src/platform_io.rs b/imgui/src/platform_io.rs index 191251c..69aab2b 100644 --- a/imgui/src/platform_io.rs +++ b/imgui/src/platform_io.rs @@ -1,6 +1,6 @@ use std::{os::raw::{c_char, c_int}, ffi::{c_void, CStr}}; -use crate::{internal::{ImVector, RawCast}, ViewportFlags}; +use crate::{internal::{ImVector, RawCast}, ViewportFlags, Io}; #[cfg(feature = "docking")] #[repr(C)] @@ -106,13 +106,13 @@ pub trait PlatformViewportBackend: 'static { fn get_platform_ctx() -> &'static mut PlatformViewportContext { unsafe { - &mut *((*sys::igGetIO()).BackendPlatformUserData as *mut PlatformViewportContext) + &mut *((*(sys::igGetIO() as *const Io)).backend_platform_user_data as *mut PlatformViewportContext) } } fn get_renderer_ctx() -> &'static mut RendererViewportContext { unsafe { - &mut *((*sys::igGetIO()).BackendRendererUserData as *mut RendererViewportContext) + &mut *((*(sys::igGetIO() as *const Io)).backend_platform_user_data as *mut RendererViewportContext) } } @@ -132,19 +132,23 @@ pub(crate) extern "C" fn platform_set_window_pos(viewport: *mut Viewport, pos: s let ctx = get_platform_ctx(); ctx.backend.set_window_pos(unsafe{&mut *viewport}, [pos.x, pos.y]); } -pub(crate) extern "C" fn platform_get_window_pos(viewport: *mut Viewport) -> sys::ImVec2 { +pub(crate) extern "C" fn platform_get_window_pos(viewport: *mut Viewport, out_pos: *mut sys::ImVec2) { let ctx = get_platform_ctx(); let pos = ctx.backend.get_window_pos(unsafe{&mut *viewport}); - sys::ImVec2::new(pos[0], pos[1]) + unsafe { + *out_pos = sys::ImVec2::new(pos[0], pos[1]); + } } pub(crate) extern "C" fn platform_set_window_size(viewport: *mut Viewport, size: sys::ImVec2) { let ctx = get_platform_ctx(); ctx.backend.set_window_size(unsafe{&mut *viewport}, [size.x, size.y]); } -pub(crate) extern "C" fn platform_get_window_size(viewport: *mut Viewport) -> sys::ImVec2 { +pub(crate) extern "C" fn platform_get_window_size(viewport: *mut Viewport, out_size: *mut sys::ImVec2) { let ctx = get_platform_ctx(); let size = ctx.backend.get_window_size(unsafe{&mut *viewport}); - sys::ImVec2::new(size[0], size[1]) + unsafe { + *out_size = sys::ImVec2::new(size[0], size[1]); + } } pub(crate) extern "C" fn platform_set_window_focus(viewport: *mut Viewport) { let ctx = get_platform_ctx(); @@ -416,3 +420,8 @@ fn test_platform_monitor_memory_layout() { assert_field_offset!(work_size, WorkSize); assert_field_offset!(dpi_scale, DpiScale); } + +extern "C" { + pub(crate) fn ImGuiPlatformIO_Set_Platform_GetWindowPos(pio: *mut PlatformIo, func: extern "C" fn(*mut Viewport, *mut sys::ImVec2)); + pub(crate) fn ImGuiPlatformIO_Set_Platform_GetWindowSize(pio: *mut PlatformIo, func: extern "C" fn(*mut Viewport, *mut sys::ImVec2)); +} From b6617b2c0e06d58885ab9fa8e2a577625bf27f4e Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Tue, 1 Mar 2022 10:23:59 +0100 Subject: [PATCH 05/42] WIP --- imgui-examples/examples/support/mod.rs | 10 +++- imgui-winit-support/src/lib.rs | 69 ++++++++++++++++++++------ imgui/src/context.rs | 21 +++++++- imgui/src/lib.rs | 1 + 4 files changed, 82 insertions(+), 19 deletions(-) diff --git a/imgui-examples/examples/support/mod.rs b/imgui-examples/examples/support/mod.rs index 546c4dc..bbbe347 100644 --- a/imgui-examples/examples/support/mod.rs +++ b/imgui-examples/examples/support/mod.rs @@ -158,13 +158,19 @@ impl System { renderer .render(&mut target, draw_data) .expect("Rendering failed"); - imgui.update_platform_windows(); target.finish().expect("Failed to swap buffers"); + + imgui.update_platform_windows(); + imgui.render_platform_windows_default(); } Event::WindowEvent { event: WindowEvent::CloseRequested, + window_id, .. - } => *control_flow = ControlFlow::Exit, + } if window_id == display.gl_window().window().id() => *control_flow = ControlFlow::Exit, + Event::WindowEvent { event, window_id, .. } if window_id != display.gl_window().window().id() => { + platform.handle_viewport_event(&mut imgui, window_id, &event); + }, event => { let gl_window = display.gl_window(); platform.handle_event(imgui.io_mut(), gl_window.window(), &event); diff --git a/imgui-winit-support/src/lib.rs b/imgui-winit-support/src/lib.rs index 83dd78c..3a009c5 100644 --- a/imgui-winit-support/src/lib.rs +++ b/imgui-winit-support/src/lib.rs @@ -188,8 +188,10 @@ use winit_20 as winit; ))] use winit_19 as winit; -use imgui::{self, BackendFlags, ConfigFlags, Context, Io, Key, Ui, PlatformViewportBackend, ViewportFlags, PlatformMonitor, Viewport}; -use std::cell::Cell; +use imgui::{self, BackendFlags, ConfigFlags, Context, Io, Key, Ui, PlatformViewportBackend, ViewportFlags, PlatformMonitor}; +use std::collections::hash_map::DefaultHasher; +use std::hash::{Hash, Hasher}; +use std::{cell::Cell, ptr::null_mut}; use std::cmp::Ordering; use winit::dpi::{LogicalPosition, LogicalSize}; @@ -466,51 +468,56 @@ impl PlatformViewportBackend for ViewportBackend { fn create_window(&mut self, viewport: &mut imgui::Viewport) { let window = winit::window::WindowBuilder::new() .with_always_on_top(viewport.flags.contains(ViewportFlags::TOP_MOST)) - .with_decorations(!viewport.flags.contains(ViewportFlags::NO_DECORATION)) + // .with_decorations(!viewport.flags.contains(ViewportFlags::NO_DECORATION)) .with_resizable(true) .with_visible(false) .build(unsafe{&*self.event_loop}) .unwrap(); - viewport.platform_handle = Box::into_raw(Box::new(PlatformHandle::SecondaryWindow(window))) as *mut _; + let mut hasher = DefaultHasher::new(); + viewport.platform_handle = window.id().hash(&hasher); + viewport.platform_handle = hasher.finish() as *mut c_void; + + viewport.platform_user_data = Box::into_raw(Box::new(PlatformHandle::SecondaryWindow(window))) as *mut _; } fn destroy_window(&mut self, viewport: &mut imgui::Viewport) { unsafe { // drop window - Box::from_raw(viewport.platform_handle as *mut PlatformHandle); + Box::from_raw(viewport.platform_user_data as *mut PlatformHandle); + viewport.platform_user_data = null_mut(); // satisfy ImGui check } } fn show_window(&mut self, viewport: &mut imgui::Viewport) { - let window = unsafe { (*(viewport.platform_handle as *const PlatformHandle)).get() }; + let window = unsafe { (*(viewport.platform_user_data as *const PlatformHandle)).get() }; window.set_visible(true); } fn set_window_pos(&mut self, viewport: &mut imgui::Viewport, pos: [f32; 2]) { - let window = unsafe { (*(viewport.platform_handle as *const PlatformHandle)).get() }; + let window = unsafe { (*(viewport.platform_user_data as *const PlatformHandle)).get() }; window.set_outer_position(winit::dpi::LogicalPosition::new(pos[0], pos[1])); } fn get_window_pos(&mut self, viewport: &mut imgui::Viewport) -> [f32; 2] { - let window = unsafe { (*(viewport.platform_handle as *const PlatformHandle)).get() }; + let window = unsafe { (*(viewport.platform_user_data as *const PlatformHandle)).get() }; let pos = window.outer_position().unwrap(); [pos.x as f32, pos.y as f32] } fn set_window_size(&mut self, viewport: &mut imgui::Viewport, size: [f32; 2]) { - let window = unsafe { (*(viewport.platform_handle as *const PlatformHandle)).get() }; + let window = unsafe { (*(viewport.platform_user_data as *const PlatformHandle)).get() }; window.set_inner_size(winit::dpi::LogicalSize::new(size[0], size[1])); } fn get_window_size(&mut self, viewport: &mut imgui::Viewport) -> [f32; 2] { - let window = unsafe { (*(viewport.platform_handle as *const PlatformHandle)).get() }; + let window = unsafe { (*(viewport.platform_user_data as *const PlatformHandle)).get() }; let size = window.inner_size(); [size.width as f32, size.width as f32] } fn set_window_focus(&mut self, viewport: &mut imgui::Viewport) { - let window = unsafe { (*(viewport.platform_handle as *const PlatformHandle)).get() }; + let window = unsafe { (*(viewport.platform_user_data as *const PlatformHandle)).get() }; window.focus_window(); } @@ -523,7 +530,7 @@ impl PlatformViewportBackend for ViewportBackend { } fn set_window_title(&mut self, viewport: &mut imgui::Viewport, title: &str) { - let window = unsafe { (*(viewport.platform_handle as *const PlatformHandle)).get() }; + let window = unsafe { (*(viewport.platform_user_data as *const PlatformHandle)).get() }; window.set_title(title); } @@ -618,9 +625,10 @@ impl WinitPlatform { pio.monitors.replace_from_slice(&monitors); let main_viewport = imgui.main_viewport_mut(); - main_viewport.platform_handle = Box::into_raw(Box::new(PlatformHandle::MainWindow(main_window as *const _))) as *mut _; - println!("MAIN VIEWPORT: {:016X}", main_viewport as *mut Viewport as u64); - println!("PLATFORM HANDLE: {:016X}", main_viewport.platform_handle as u64); + let mut hasher = DefaultHasher::new(); + main_window.id().hash(&mut hasher); + main_viewport.platform_handle = hasher.finish() as *mut c_void; + main_viewport.platform_user_data = Box::into_raw(Box::new(PlatformHandle::MainWindow(main_window as *const _))) as *mut _; } /// Attaches the platform instance to a winit window. @@ -979,6 +987,37 @@ impl WinitPlatform { _ => (), } } + pub fn handle_viewport_event(&mut self, imgui: &mut imgui::Context, window_id: winit::window::WindowId, window_event: &winit::event::WindowEvent) { + let hasher = DefaultHasher::new(); + window_id.hash(&mut hasher); + let viewport_id = hasher.finish(); + + match *window_event { + WindowEvent::Resized(new_size) => { + + }, + WindowEvent::Moved(_) => todo!(), + WindowEvent::CloseRequested => todo!(), + WindowEvent::Destroyed => todo!(), + WindowEvent::DroppedFile(_) => todo!(), + WindowEvent::HoveredFile(_) => todo!(), + WindowEvent::HoveredFileCancelled => todo!(), + WindowEvent::ReceivedCharacter(_) => todo!(), + WindowEvent::Focused(_) => todo!(), + WindowEvent::KeyboardInput { device_id, input, is_synthetic } => todo!(), + WindowEvent::ModifiersChanged(_) => todo!(), + WindowEvent::CursorMoved { device_id, position, modifiers } => todo!(), + WindowEvent::CursorEntered { device_id } => todo!(), + WindowEvent::CursorLeft { device_id } => todo!(), + WindowEvent::MouseWheel { device_id, delta, phase, modifiers } => todo!(), + WindowEvent::MouseInput { device_id, state, button, modifiers } => todo!(), + WindowEvent::TouchpadPressure { device_id, pressure, stage } => todo!(), + WindowEvent::AxisMotion { device_id, axis, value } => todo!(), + WindowEvent::Touch(_) => todo!(), + WindowEvent::ScaleFactorChanged { scale_factor, new_inner_size } => todo!(), + WindowEvent::ThemeChanged(_) => todo!(), + } + } #[cfg(all( not(any( feature = "winit-26", diff --git a/imgui/src/context.rs b/imgui/src/context.rs index a233795..e822b83 100644 --- a/imgui/src/context.rs +++ b/imgui/src/context.rs @@ -1,9 +1,9 @@ use parking_lot::ReentrantMutex; use std::cell::UnsafeCell; -use std::ffi::{CStr, CString}; +use std::ffi::{CStr, CString, c_void}; use std::ops::Drop; use std::path::PathBuf; -use std::ptr; +use std::ptr::{self, null_mut}; use crate::clipboard::{ClipboardBackend, ClipboardContext}; use crate::fonts::atlas::{FontAtlas, FontId, SharedFontAtlas}; @@ -275,6 +275,11 @@ impl Context { sys::igUpdatePlatformWindows(); } } + pub fn render_platform_windows_default(&mut self) { + unsafe { + sys::igRenderPlatformWindowsDefault(null_mut(), null_mut()); + } + } fn create_internal(mut shared_font_atlas: Option) -> Self { let _guard = CTX_MUTEX.lock(); assert!( @@ -564,6 +569,18 @@ impl Context { &mut *(sys::igGetMainViewport() as *mut Viewport) } } + pub fn viewport_by_id(&self, id: *mut c_void) -> Option<&Viewport> { + unsafe { + let ptr = sys::igFindViewportByPlatformHandle(id) as *const Viewport; + ptr.as_ref() + } + } + pub fn viewport_by_id_mut(&mut self, id: *mut c_void) -> Option<&mut Viewport> { + unsafe { + let ptr = sys::igFindViewportByPlatformHandle(id) as *mut Viewport; + ptr.as_mut() + } + } /// Returns an immutable reference to the user interface style #[doc(alias = "GetStyle")] pub fn style(&self) -> &Style { diff --git a/imgui/src/lib.rs b/imgui/src/lib.rs index b80a2ca..e3d0a31 100644 --- a/imgui/src/lib.rs +++ b/imgui/src/lib.rs @@ -283,6 +283,7 @@ impl Ui { /// Previously, this was erroneously constructed with `From` implementations. /// Now, however, it is made from the `Ui` object directly, with a few /// deprecated helper methods here. +#[repr(transparent)] #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] pub struct Id(pub(crate) u32); From cf214ca397814fb9e4ab1c449be6e8b1a4306524 Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Tue, 1 Mar 2022 11:26:36 +0100 Subject: [PATCH 06/42] Reverted integration changes --- imgui-examples/examples/hello_world.rs | 3 +- imgui-examples/examples/support/mod.rs | 16 +-- imgui-winit-support/src/lib.rs | 175 +------------------------ 3 files changed, 5 insertions(+), 189 deletions(-) diff --git a/imgui-examples/examples/hello_world.rs b/imgui-examples/examples/hello_world.rs index 4a70e86..8728558 100644 --- a/imgui-examples/examples/hello_world.rs +++ b/imgui-examples/examples/hello_world.rs @@ -3,8 +3,7 @@ use imgui::*; mod support; fn main() { - let mut system = support::init(file!()); - system.enable_viewports(); + let system = support::init(file!()); let mut value = 0; let choices = ["test test this is 1", "test test this is 2"]; diff --git a/imgui-examples/examples/support/mod.rs b/imgui-examples/examples/support/mod.rs index bbbe347..44e8825 100644 --- a/imgui-examples/examples/support/mod.rs +++ b/imgui-examples/examples/support/mod.rs @@ -3,7 +3,7 @@ use glium::glutin::event::{Event, WindowEvent}; use glium::glutin::event_loop::{ControlFlow, EventLoop}; use glium::glutin::window::WindowBuilder; use glium::{Display, Surface}; -use imgui::{Context, FontConfig, FontGlyphRanges, FontSource, Ui, ConfigFlags}; +use imgui::{Context, FontConfig, FontGlyphRanges, FontSource, Ui}; use imgui_glium_renderer::Renderer; use imgui_winit_support::{HiDpiMode, WinitPlatform}; use std::path::Path; @@ -112,11 +112,6 @@ pub fn init(title: &str) -> System { } impl System { - pub fn enable_viewports(&mut self) { - WinitPlatform::init_viewports(&mut self.imgui, &self.event_loop, self.display.gl_window().window()); - self.imgui.io_mut().config_flags.insert(ConfigFlags::VIEWPORTS_ENABLE); - } - pub fn main_loop(self, mut run_ui: F) { let System { event_loop, @@ -159,18 +154,11 @@ impl System { .render(&mut target, draw_data) .expect("Rendering failed"); target.finish().expect("Failed to swap buffers"); - - imgui.update_platform_windows(); - imgui.render_platform_windows_default(); } Event::WindowEvent { event: WindowEvent::CloseRequested, - window_id, .. - } if window_id == display.gl_window().window().id() => *control_flow = ControlFlow::Exit, - Event::WindowEvent { event, window_id, .. } if window_id != display.gl_window().window().id() => { - platform.handle_viewport_event(&mut imgui, window_id, &event); - }, + } => *control_flow = ControlFlow::Exit, event => { let gl_window = display.gl_window(); platform.handle_event(imgui.io_mut(), gl_window.window(), &event); diff --git a/imgui-winit-support/src/lib.rs b/imgui-winit-support/src/lib.rs index 3a009c5..3c2c65d 100644 --- a/imgui-winit-support/src/lib.rs +++ b/imgui-winit-support/src/lib.rs @@ -188,10 +188,8 @@ use winit_20 as winit; ))] use winit_19 as winit; -use imgui::{self, BackendFlags, ConfigFlags, Context, Io, Key, Ui, PlatformViewportBackend, ViewportFlags, PlatformMonitor}; -use std::collections::hash_map::DefaultHasher; -use std::hash::{Hash, Hasher}; -use std::{cell::Cell, ptr::null_mut}; +use imgui::{self, BackendFlags, ConfigFlags, Context, Io, Key, Ui}; +use std::cell::Cell; use std::cmp::Ordering; use winit::dpi::{LogicalPosition, LogicalSize}; @@ -446,115 +444,6 @@ impl HiDpiMode { } } -struct ViewportBackend { - event_loop: *const winit::event_loop::EventLoopWindowTarget<()>, -} - -enum PlatformHandle { - MainWindow(*const winit::window::Window), - SecondaryWindow(winit::window::Window), -} - -impl PlatformHandle { - fn get(&self) -> &winit::window::Window { - match self { - PlatformHandle::MainWindow(ptr) => unsafe { &**ptr }, - PlatformHandle::SecondaryWindow(wnd) => wnd, - } - } -} - -impl PlatformViewportBackend for ViewportBackend { - fn create_window(&mut self, viewport: &mut imgui::Viewport) { - let window = winit::window::WindowBuilder::new() - .with_always_on_top(viewport.flags.contains(ViewportFlags::TOP_MOST)) - // .with_decorations(!viewport.flags.contains(ViewportFlags::NO_DECORATION)) - .with_resizable(true) - .with_visible(false) - .build(unsafe{&*self.event_loop}) - .unwrap(); - - let mut hasher = DefaultHasher::new(); - viewport.platform_handle = window.id().hash(&hasher); - viewport.platform_handle = hasher.finish() as *mut c_void; - - viewport.platform_user_data = Box::into_raw(Box::new(PlatformHandle::SecondaryWindow(window))) as *mut _; - } - - fn destroy_window(&mut self, viewport: &mut imgui::Viewport) { - unsafe { - // drop window - Box::from_raw(viewport.platform_user_data as *mut PlatformHandle); - viewport.platform_user_data = null_mut(); // satisfy ImGui check - } - } - - fn show_window(&mut self, viewport: &mut imgui::Viewport) { - let window = unsafe { (*(viewport.platform_user_data as *const PlatformHandle)).get() }; - window.set_visible(true); - } - - fn set_window_pos(&mut self, viewport: &mut imgui::Viewport, pos: [f32; 2]) { - let window = unsafe { (*(viewport.platform_user_data as *const PlatformHandle)).get() }; - window.set_outer_position(winit::dpi::LogicalPosition::new(pos[0], pos[1])); - } - - fn get_window_pos(&mut self, viewport: &mut imgui::Viewport) -> [f32; 2] { - let window = unsafe { (*(viewport.platform_user_data as *const PlatformHandle)).get() }; - let pos = window.outer_position().unwrap(); - [pos.x as f32, pos.y as f32] - } - - fn set_window_size(&mut self, viewport: &mut imgui::Viewport, size: [f32; 2]) { - let window = unsafe { (*(viewport.platform_user_data as *const PlatformHandle)).get() }; - window.set_inner_size(winit::dpi::LogicalSize::new(size[0], size[1])); - } - - fn get_window_size(&mut self, viewport: &mut imgui::Viewport) -> [f32; 2] { - let window = unsafe { (*(viewport.platform_user_data as *const PlatformHandle)).get() }; - let size = window.inner_size(); - [size.width as f32, size.width as f32] - } - - fn set_window_focus(&mut self, viewport: &mut imgui::Viewport) { - let window = unsafe { (*(viewport.platform_user_data as *const PlatformHandle)).get() }; - window.focus_window(); - } - - fn get_window_focus(&mut self, _viewport: &mut imgui::Viewport) -> bool { - true - } - - fn get_window_minimized(&mut self, _viewport: &mut imgui::Viewport) -> bool { - false - } - - fn set_window_title(&mut self, viewport: &mut imgui::Viewport, title: &str) { - let window = unsafe { (*(viewport.platform_user_data as *const PlatformHandle)).get() }; - window.set_title(title); - } - - fn set_window_alpha(&mut self, _viewport: &mut imgui::Viewport, _alpha: f32) { - - } - - fn update_window(&mut self, _viewport: &mut imgui::Viewport) { - - } - - fn render_window(&mut self, _viewport: &mut imgui::Viewport) { - - } - - fn swap_buffers(&mut self, _viewport: &mut imgui::Viewport) { - - } - - fn create_vk_surface(&mut self, _viewport: &mut imgui::Viewport, _instance: u64, _out_surface: &mut u64) -> i32 { - 0 - } -} - impl WinitPlatform { /// Initializes a winit platform instance and configures imgui. /// @@ -602,35 +491,6 @@ impl WinitPlatform { mouse_buttons: [Button::INIT; 5], } } - - pub fn init_viewports(imgui: &mut Context, event_loop: &winit::event_loop::EventLoopWindowTarget<()>, main_window: &winit::window::Window) { - let io = imgui.io_mut(); - io.backend_flags.insert(BackendFlags::PLATFORM_HAS_VIEWPORTS); - - imgui.set_platform_backend(ViewportBackend{ - event_loop: event_loop as *const _, - }); - - let pio = imgui.platform_io_mut(); - let mut monitors = Vec::new(); - for monitor in main_window.available_monitors() { - monitors.push(PlatformMonitor { - main_pos: [monitor.position().x as f32, monitor.position().y as f32], - main_size: [monitor.size().width as f32, monitor.size().height as f32], - work_pos: [monitor.position().x as f32, monitor.position().y as f32], - work_size: [monitor.size().width as f32, monitor.size().height as f32], - dpi_scale: 1.0, - }); - } - pio.monitors.replace_from_slice(&monitors); - - let main_viewport = imgui.main_viewport_mut(); - let mut hasher = DefaultHasher::new(); - main_window.id().hash(&mut hasher); - main_viewport.platform_handle = hasher.finish() as *mut c_void; - main_viewport.platform_user_data = Box::into_raw(Box::new(PlatformHandle::MainWindow(main_window as *const _))) as *mut _; - } - /// Attaches the platform instance to a winit window. /// /// This function configures imgui-rs in the following ways: @@ -987,37 +847,6 @@ impl WinitPlatform { _ => (), } } - pub fn handle_viewport_event(&mut self, imgui: &mut imgui::Context, window_id: winit::window::WindowId, window_event: &winit::event::WindowEvent) { - let hasher = DefaultHasher::new(); - window_id.hash(&mut hasher); - let viewport_id = hasher.finish(); - - match *window_event { - WindowEvent::Resized(new_size) => { - - }, - WindowEvent::Moved(_) => todo!(), - WindowEvent::CloseRequested => todo!(), - WindowEvent::Destroyed => todo!(), - WindowEvent::DroppedFile(_) => todo!(), - WindowEvent::HoveredFile(_) => todo!(), - WindowEvent::HoveredFileCancelled => todo!(), - WindowEvent::ReceivedCharacter(_) => todo!(), - WindowEvent::Focused(_) => todo!(), - WindowEvent::KeyboardInput { device_id, input, is_synthetic } => todo!(), - WindowEvent::ModifiersChanged(_) => todo!(), - WindowEvent::CursorMoved { device_id, position, modifiers } => todo!(), - WindowEvent::CursorEntered { device_id } => todo!(), - WindowEvent::CursorLeft { device_id } => todo!(), - WindowEvent::MouseWheel { device_id, delta, phase, modifiers } => todo!(), - WindowEvent::MouseInput { device_id, state, button, modifiers } => todo!(), - WindowEvent::TouchpadPressure { device_id, pressure, stage } => todo!(), - WindowEvent::AxisMotion { device_id, axis, value } => todo!(), - WindowEvent::Touch(_) => todo!(), - WindowEvent::ScaleFactorChanged { scale_factor, new_inner_size } => todo!(), - WindowEvent::ThemeChanged(_) => todo!(), - } - } #[cfg(all( not(any( feature = "winit-26", From daf039c098333e6501a850031af8e6bac2864ebc Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Tue, 1 Mar 2022 13:38:20 +0100 Subject: [PATCH 07/42] WIP --- imgui-examples/Cargo.toml | 2 +- imgui-examples/examples/hello_world.rs | 3 +- imgui-examples/examples/support/mod.rs | 7 +- imgui-winit-support/Cargo.toml | 4 +- imgui-winit-support/src/lib.rs | 239 ++++++++++++++++++++++++- imgui/src/context.rs | 24 ++- imgui/src/lib.rs | 2 +- imgui/src/platform_io.rs | 2 +- 8 files changed, 269 insertions(+), 14 deletions(-) diff --git a/imgui-examples/Cargo.toml b/imgui-examples/Cargo.toml index 639b0ba..148d06c 100644 --- a/imgui-examples/Cargo.toml +++ b/imgui-examples/Cargo.toml @@ -15,4 +15,4 @@ glium = { version = "0.31", default-features = true } image = "0.23" imgui = { path = "../imgui", features = ["tables-api", "docking"] } imgui-glium-renderer = { path = "../imgui-glium-renderer" } -imgui-winit-support = { path = "../imgui-winit-support" } +imgui-winit-support = { path = "../imgui-winit-support", features=["viewports"] } diff --git a/imgui-examples/examples/hello_world.rs b/imgui-examples/examples/hello_world.rs index 8728558..0b21816 100644 --- a/imgui-examples/examples/hello_world.rs +++ b/imgui-examples/examples/hello_world.rs @@ -3,7 +3,8 @@ use imgui::*; mod support; fn main() { - let system = support::init(file!()); + let mut system = support::init(file!()); + system.imgui.io_mut().config_flags.insert(ConfigFlags::VIEWPORTS_ENABLE); let mut value = 0; let choices = ["test test this is 1", "test test this is 2"]; diff --git a/imgui-examples/examples/support/mod.rs b/imgui-examples/examples/support/mod.rs index 44e8825..0924593 100644 --- a/imgui-examples/examples/support/mod.rs +++ b/imgui-examples/examples/support/mod.rs @@ -43,6 +43,7 @@ pub fn init(title: &str) -> System { } let mut platform = WinitPlatform::init(&mut imgui); + WinitPlatform::init_viewports(&mut imgui, &event_loop); { let gl_window = display.gl_window(); let window = gl_window.window(); @@ -123,7 +124,7 @@ impl System { } = self; let mut last_frame = Instant::now(); - event_loop.run(move |event, _, control_flow| match event { + event_loop.run(move |event, window_target, control_flow| match event { Event::NewEvents(_) => { let now = Instant::now(); imgui.io_mut().update_delta_time(now - last_frame); @@ -154,6 +155,9 @@ impl System { .render(&mut target, draw_data) .expect("Rendering failed"); target.finish().expect("Failed to swap buffers"); + + imgui.update_platform_windows(); + platform.update_viewports(&mut imgui, window_target); } Event::WindowEvent { event: WindowEvent::CloseRequested, @@ -162,6 +166,7 @@ impl System { event => { let gl_window = display.gl_window(); platform.handle_event(imgui.io_mut(), gl_window.window(), &event); + platform.handle_viewport_event(&mut imgui, gl_window.window(), &event); } }) } diff --git a/imgui-winit-support/Cargo.toml b/imgui-winit-support/Cargo.toml index e105b0e..f9ca765 100644 --- a/imgui-winit-support/Cargo.toml +++ b/imgui-winit-support/Cargo.toml @@ -20,9 +20,11 @@ winit-25 = { version = "0.25", package = "winit", default-features = false, opti winit-26 = { version = "0.26", package = "winit", default-features = false, optional = true } [features] -default = ["winit-26/default"] +default = ["winit-26/default", "viewports"] test = ["winit-23/default", "winit-24/default", "winit-25/default", "winit-26/default"] +viewports = [ "imgui/docking" ] + # This is phrased as a negative (unlike most features) so that it needs to be # explicitly disabled (and `default-features = false` won't do it). To avoid # problems from this we don't expose this in the public API in any way, keeping diff --git a/imgui-winit-support/src/lib.rs b/imgui-winit-support/src/lib.rs index 3c2c65d..7f311ca 100644 --- a/imgui-winit-support/src/lib.rs +++ b/imgui-winit-support/src/lib.rs @@ -189,7 +189,7 @@ use winit_20 as winit; use winit_19 as winit; use imgui::{self, BackendFlags, ConfigFlags, Context, Io, Key, Ui}; -use std::cell::Cell; +use std::{cell::Cell, collections::HashMap}; use std::cmp::Ordering; use winit::dpi::{LogicalPosition, LogicalSize}; @@ -342,6 +342,9 @@ pub struct WinitPlatform { hidpi_factor: f64, cursor_cache: Option, mouse_buttons: [Button; 5], + + #[cfg(feature = "viewports")] + windows: HashMap, } #[derive(Debug, Copy, Clone, Eq, PartialEq)] @@ -444,6 +447,107 @@ impl HiDpiMode { } } +#[cfg(feature = "viewports")] +struct ViewportBackend {} + +#[cfg(feature = "viewports")] +impl imgui::PlatformViewportBackend for ViewportBackend { + fn create_window(&mut self, viewport: &mut imgui::Viewport) { + viewport.platform_user_data = Box::into_raw(Box::new(ViewportState { + create: true, + create_flags: viewport.flags, + set_show: false, + set_pos: None, + set_size: None, + set_focus: false, + set_title: None, + pos: [0.0, 0.0], + size: [0.0, 0.0], + focus: false, + minimized: false, + })) as *mut _; + } + + fn destroy_window(&mut self, viewport: &mut imgui::Viewport) { + unsafe { + Box::from_raw(viewport.platform_user_data as *mut ViewportState); + } + viewport.platform_user_data = std::ptr::null_mut(); + } + + fn show_window(&mut self, viewport: &mut imgui::Viewport) { + let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + state.set_show = true; + } + + fn set_window_pos(&mut self, viewport: &mut imgui::Viewport, pos: [f32; 2]) { + let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + state.set_pos = Some(pos); + } + + fn get_window_pos(&mut self, viewport: &mut imgui::Viewport) -> [f32; 2] { + let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + state.pos + } + + fn set_window_size(&mut self, viewport: &mut imgui::Viewport, size: [f32; 2]) { + let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + state.set_size = Some(size); + } + + fn get_window_size(&mut self, viewport: &mut imgui::Viewport) -> [f32; 2] { + let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + state.size + } + + fn set_window_focus(&mut self, viewport: &mut imgui::Viewport) { + let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + state.set_focus = true; + } + + fn get_window_focus(&mut self, viewport: &mut imgui::Viewport) -> bool { + let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + state.focus + } + + fn get_window_minimized(&mut self, viewport: &mut imgui::Viewport) -> bool { + let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + state.focus + } + + fn set_window_title(&mut self, viewport: &mut imgui::Viewport, title: &str) { + let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + state.set_title = Some(title.to_string()); + } + + fn set_window_alpha(&mut self, _viewport: &mut imgui::Viewport, _alpha: f32) {} + + fn update_window(&mut self, _viewport: &mut imgui::Viewport) {} + + fn render_window(&mut self, _viewport: &mut imgui::Viewport) {} + + fn swap_buffers(&mut self, _viewport: &mut imgui::Viewport) {} + + fn create_vk_surface(&mut self, _viewport: &mut imgui::Viewport, _instance: u64, _out_surface: &mut u64) -> i32 { 0 } +} + +#[cfg(feature = "viewports")] +struct ViewportState { + create: bool, + create_flags: imgui::ViewportFlags, + + set_show: bool, + set_pos: Option<[f32; 2]>, + set_size: Option<[f32; 2]>, + set_focus: bool, + set_title: Option, + + pos: [f32; 2], + size: [f32; 2], + focus: bool, + minimized: bool, +} + impl WinitPlatform { /// Initializes a winit platform instance and configures imgui. /// @@ -489,8 +593,102 @@ impl WinitPlatform { hidpi_factor: 1.0, cursor_cache: None, mouse_buttons: [Button::INIT; 5], + + #[cfg(feature = "viewports")] + windows: HashMap::new(), } } + + #[cfg(feature = "viewports")] + pub fn init_viewports(imgui: &mut Context, event_loop: &winit::event_loop::EventLoop) { + let io = imgui.io_mut(); + + io.backend_flags.insert(BackendFlags::PLATFORM_HAS_VIEWPORTS); + + imgui.set_platform_backend(ViewportBackend {}); + + let mut monitors = Vec::new(); + for monitor in event_loop.available_monitors() { + monitors.push(imgui::PlatformMonitor { + main_pos: [monitor.position().x as f32, monitor.position().y as f32], + main_size: [monitor.size().width as f32, monitor.size().height as f32], + work_pos: [monitor.position().x as f32, monitor.position().y as f32], + work_size: [monitor.size().width as f32, monitor.size().height as f32], + dpi_scale: 1.0, + }); + } + imgui.platform_io_mut().monitors.replace_from_slice(&monitors); + + let main_viewport = imgui.main_viewport_mut(); + main_viewport.platform_user_data = Box::into_raw(Box::new(ViewportState { + create: false, + create_flags: imgui::ViewportFlags::empty(), + set_show: false, + set_pos: None, + set_size: None, + set_focus: false, + set_title: None, + pos: [0.0, 0.0], + size: [0.0, 0.0], + focus: true, + minimized: false, + })) as *mut _; + } + + #[cfg(feature = "viewports")] + pub fn update_viewports(&mut self, imgui: &mut Context, window_target: &winit::event_loop::EventLoopWindowTarget) { + // remove destroyed windows + self.windows.retain(|id, _| { + imgui.viewport_by_id(*id).is_some() + }); + + // handle new viewports + for viewport in imgui.viewports_mut() { + let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + + if state.create { + let window = winit::window::WindowBuilder::new() + .with_always_on_top(state.create_flags.contains(imgui::ViewportFlags::TOP_MOST)) + // .with_decorations(!state.create_flags.contains(imgui::ViewportFlags::NO_DECORATION)) + .with_resizable(true) + .with_visible(false) + .build(window_target) + .unwrap(); + + self.windows.insert(viewport.id, window); + + state.create = false; + } + } + + // handle other viewport events + for (id, wnd) in &self.windows { + let viewport = imgui.viewport_by_id_mut(*id).unwrap(); + let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + + if state.set_show { + wnd.set_visible(true); + state.set_show = false; + } + if let Some(pos) = &state.set_pos { + wnd.set_outer_position(winit::dpi::LogicalPosition::new(pos[0], pos[1])); + state.set_pos = None; + } + if let Some(size) = &state.set_size { + wnd.set_inner_size(winit::dpi::LogicalSize::new(size[0], size[1])); + state.set_size = None; + } + if state.set_focus { + wnd.focus_window(); + state.set_focus = false; + } + if let Some(title) = &state.set_title { + wnd.set_title(title); + state.set_title = None; + } + } + } + /// Attaches the platform instance to a winit window. /// /// This function configures imgui-rs in the following ways: @@ -847,6 +1045,45 @@ impl WinitPlatform { _ => (), } } + #[cfg(feature = "viewports")] + pub fn handle_viewport_event(&mut self, imgui: &mut imgui::Context, main_window: &Window, event: &Event) { + match *event { + Event::WindowEvent { window_id, ref event } => { + let viewport = { + if window_id == main_window.id() { + imgui.main_viewport_mut() + } else { + let imgui_id = self.windows.iter().find(|(id, wnd)| wnd.id() == window_id).map(|(id, wnd)| *id).unwrap(); + imgui.viewport_by_id_mut(imgui_id).unwrap() + } + }; + let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + + match *event { + WindowEvent::Resized(new_size) => { + state.size = [new_size.width as f32, new_size.height as f32]; + }, + WindowEvent::Moved(new_pos) => { + state.pos = [new_pos.x as f32, new_pos.y as f32]; + }, + WindowEvent::CloseRequested => { + viewport.platform_request_close = true; + }, + WindowEvent::Focused(focus) => { + state.focus = focus; + }, + WindowEvent::CursorMoved { position, .. } => { + let mut pos = state.pos; + pos[0] += position.x as f32; + pos[1] += position.y as f32; + imgui.io_mut().mouse_pos = pos; + }, + _ => {}, + } + }, + _ => {}, + } + } #[cfg(all( not(any( feature = "winit-26", diff --git a/imgui/src/context.rs b/imgui/src/context.rs index e822b83..00d780a 100644 --- a/imgui/src/context.rs +++ b/imgui/src/context.rs @@ -9,7 +9,7 @@ use crate::clipboard::{ClipboardBackend, ClipboardContext}; use crate::fonts::atlas::{FontAtlas, FontId, SharedFontAtlas}; use crate::io::Io; use crate::style::Style; -use crate::{sys, DrawData, PlatformIo, PlatformViewportContext, RendererViewportContext, PlatformViewportBackend, RendererViewportBackend, Viewport}; +use crate::{sys, DrawData, PlatformIo, PlatformViewportContext, RendererViewportContext, PlatformViewportBackend, RendererViewportBackend, Viewport, Id}; use crate::{MouseCursor, Ui}; /// An imgui-rs context. @@ -569,16 +569,26 @@ impl Context { &mut *(sys::igGetMainViewport() as *mut Viewport) } } - pub fn viewport_by_id(&self, id: *mut c_void) -> Option<&Viewport> { + pub fn viewport_by_id(&self, id: Id) -> Option<&Viewport> { unsafe { - let ptr = sys::igFindViewportByPlatformHandle(id) as *const Viewport; - ptr.as_ref() + (sys::igFindViewportByID(id.0) as *const Viewport).as_ref() } } - pub fn viewport_by_id_mut(&mut self, id: *mut c_void) -> Option<&mut Viewport> { + pub fn viewport_by_id_mut(&mut self, id: Id) -> Option<&mut Viewport> { unsafe { - let ptr = sys::igFindViewportByPlatformHandle(id) as *mut Viewport; - ptr.as_mut() + (sys::igFindViewportByID(id.0) as *mut Viewport).as_mut() + } + } + pub fn viewports(&self) -> impl Iterator { + let slice = self.platform_io().viewports.as_slice(); + unsafe { + slice.iter().map(|ptr| &**ptr) + } + } + pub fn viewports_mut(&mut self) -> impl Iterator { + let slice = self.platform_io_mut().viewports.as_slice(); + unsafe { + slice.iter().map(|ptr| &mut **ptr) } } /// Returns an immutable reference to the user interface style diff --git a/imgui/src/lib.rs b/imgui/src/lib.rs index e3d0a31..6958686 100644 --- a/imgui/src/lib.rs +++ b/imgui/src/lib.rs @@ -284,7 +284,7 @@ impl Ui { /// Now, however, it is made from the `Ui` object directly, with a few /// deprecated helper methods here. #[repr(transparent)] -#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Default, Hash)] pub struct Id(pub(crate) u32); impl Id { diff --git a/imgui/src/platform_io.rs b/imgui/src/platform_io.rs index 69aab2b..9e0c696 100644 --- a/imgui/src/platform_io.rs +++ b/imgui/src/platform_io.rs @@ -334,7 +334,7 @@ impl RendererViewportContext { #[cfg(feature = "docking")] #[repr(C)] pub struct Viewport { - pub(crate) id: crate::Id, + pub id: crate::Id, pub flags: ViewportFlags, pub(crate) pos: [f32; 2], pub(crate) size: [f32; 2], From 0e9f39c942b2555ba4a0dfd2440dae7515c79798 Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Tue, 1 Mar 2022 14:24:31 +0100 Subject: [PATCH 08/42] More WIP --- imgui-examples/examples/hello_world.rs | 3 + imgui-examples/examples/support/mod.rs | 6 +- imgui-winit-support/src/lib.rs | 76 +++++++++++++++++++++++++- 3 files changed, 82 insertions(+), 3 deletions(-) diff --git a/imgui-examples/examples/hello_world.rs b/imgui-examples/examples/hello_world.rs index 0b21816..ddb85f8 100644 --- a/imgui-examples/examples/hello_world.rs +++ b/imgui-examples/examples/hello_world.rs @@ -8,8 +8,11 @@ fn main() { let mut value = 0; let choices = ["test test this is 1", "test test this is 2"]; + let mut open = true; + system.main_loop(move |_, ui| { ui.window("Hello world") + .opened(&mut open) .size([300.0, 110.0], Condition::FirstUseEver) .build(|| { ui.text_wrapped("Hello world!"); diff --git a/imgui-examples/examples/support/mod.rs b/imgui-examples/examples/support/mod.rs index 0924593..aacd200 100644 --- a/imgui-examples/examples/support/mod.rs +++ b/imgui-examples/examples/support/mod.rs @@ -136,6 +136,8 @@ impl System { .prepare_frame(imgui.io_mut(), gl_window.window()) .expect("Failed to prepare frame"); gl_window.window().request_redraw(); + + platform.update_viewports(&mut imgui, window_target); } Event::RedrawRequested(_) => { let ui = imgui.frame(); @@ -157,12 +159,12 @@ impl System { target.finish().expect("Failed to swap buffers"); imgui.update_platform_windows(); - platform.update_viewports(&mut imgui, window_target); } Event::WindowEvent { event: WindowEvent::CloseRequested, + window_id, .. - } => *control_flow = ControlFlow::Exit, + } if window_id == display.gl_window().window().id() => *control_flow = ControlFlow::Exit, event => { let gl_window = display.gl_window(); platform.handle_event(imgui.io_mut(), gl_window.window(), &event); diff --git a/imgui-winit-support/src/lib.rs b/imgui-winit-support/src/lib.rs index 7f311ca..4239fac 100644 --- a/imgui-winit-support/src/lib.rs +++ b/imgui-winit-support/src/lib.rs @@ -1053,7 +1053,7 @@ impl WinitPlatform { if window_id == main_window.id() { imgui.main_viewport_mut() } else { - let imgui_id = self.windows.iter().find(|(id, wnd)| wnd.id() == window_id).map(|(id, wnd)| *id).unwrap(); + let imgui_id = self.windows.iter().find(|(_, wnd)| wnd.id() == window_id).map(|(id, _)| *id).unwrap(); imgui.viewport_by_id_mut(imgui_id).unwrap() } }; @@ -1078,12 +1078,86 @@ impl WinitPlatform { pos[1] += position.y as f32; imgui.io_mut().mouse_pos = pos; }, + WindowEvent::KeyboardInput { + input: + KeyboardInput { + virtual_keycode: Some(key), + state, + .. + }, + .. + } if window_id != main_window.id() => { + let io = imgui.io_mut(); + + let pressed = state == ElementState::Pressed; + io.keys_down[key as usize] = pressed; + + // This is a bit redundant here, but we'll leave it in. The OS occasionally + // fails to send modifiers keys, but it doesn't seem to send false-positives, + // so double checking isn't terrible in case some system *doesn't* send + // device events sometimes. + match key { + VirtualKeyCode::LShift | VirtualKeyCode::RShift => io.key_shift = pressed, + VirtualKeyCode::LControl | VirtualKeyCode::RControl => io.key_ctrl = pressed, + VirtualKeyCode::LAlt | VirtualKeyCode::RAlt => io.key_alt = pressed, + VirtualKeyCode::LWin | VirtualKeyCode::RWin => io.key_super = pressed, + _ => (), + } + }, + WindowEvent::ReceivedCharacter(ch) if window_id != main_window.id() => { + let io = imgui.io_mut(); + + // Exclude the backspace key ('\u{7f}'). Otherwise we will insert this char and then + // delete it. + if ch != '\u{7f}' { + io.add_input_character(ch) + } + }, + WindowEvent::MouseWheel { + delta, + phase: TouchPhase::Moved, + .. + } if window_id != main_window.id() => match delta { + MouseScrollDelta::LineDelta(h, v) => { + let io = imgui.io_mut(); + io.mouse_wheel_h = h; + io.mouse_wheel = v; + } + MouseScrollDelta::PixelDelta(pos) => { + let io = imgui.io_mut(); + let pos = pos.to_logical::(self.hidpi_factor); + match pos.x.partial_cmp(&0.0) { + Some(Ordering::Greater) => io.mouse_wheel_h += 1.0, + Some(Ordering::Less) => io.mouse_wheel_h -= 1.0, + _ => (), + } + match pos.y.partial_cmp(&0.0) { + Some(Ordering::Greater) => io.mouse_wheel += 1.0, + Some(Ordering::Less) => io.mouse_wheel -= 1.0, + _ => (), + } + } + }, + WindowEvent::MouseInput { state, button, .. } if window_id != main_window.id() => { + let pressed = state == ElementState::Pressed; + match button { + MouseButton::Left => self.mouse_buttons[0].set(pressed), + MouseButton::Right => self.mouse_buttons[1].set(pressed), + MouseButton::Middle => self.mouse_buttons[2].set(pressed), + MouseButton::Other(idx @ 0..=4) => { + self.mouse_buttons[idx as usize].set(pressed) + } + _ => (), + } + }, _ => {}, } }, _ => {}, } } + + #[cfg(all( not(any( feature = "winit-26", From e68ea5fe3b26fdebbbfcffb1f6beeb9c592145d9 Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Tue, 1 Mar 2022 14:40:26 +0100 Subject: [PATCH 09/42] Fixed crashes --- imgui-examples/examples/hello_world.rs | 38 ++++++++++++++------------ imgui-winit-support/src/lib.rs | 13 ++++++--- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/imgui-examples/examples/hello_world.rs b/imgui-examples/examples/hello_world.rs index ddb85f8..42d4ce8 100644 --- a/imgui-examples/examples/hello_world.rs +++ b/imgui-examples/examples/hello_world.rs @@ -11,24 +11,26 @@ fn main() { let mut open = true; system.main_loop(move |_, ui| { - ui.window("Hello world") - .opened(&mut open) - .size([300.0, 110.0], Condition::FirstUseEver) - .build(|| { - ui.text_wrapped("Hello world!"); - ui.text_wrapped("こんにちは世界!"); - if ui.button(choices[value]) { - value += 1; - value %= 2; - } + if open { + ui.window("Hello world") + .opened(&mut open) + .size([300.0, 110.0], Condition::FirstUseEver) + .build(|| { + ui.text_wrapped("Hello world!"); + ui.text_wrapped("こんにちは世界!"); + if ui.button(choices[value]) { + value += 1; + value %= 2; + } - ui.button("This...is...imgui-rs!"); - ui.separator(); - let mouse_pos = ui.io().mouse_pos; - ui.text(format!( - "Mouse Position: ({:.1},{:.1})", - mouse_pos[0], mouse_pos[1] - )); - }); + ui.button("This...is...imgui-rs!"); + ui.separator(); + let mouse_pos = ui.io().mouse_pos; + ui.text(format!( + "Mouse Position: ({:.1},{:.1})", + mouse_pos[0], mouse_pos[1] + )); + }); + } }); } diff --git a/imgui-winit-support/src/lib.rs b/imgui-winit-support/src/lib.rs index 4239fac..a975bf6 100644 --- a/imgui-winit-support/src/lib.rs +++ b/imgui-winit-support/src/lib.rs @@ -639,7 +639,7 @@ impl WinitPlatform { pub fn update_viewports(&mut self, imgui: &mut Context, window_target: &winit::event_loop::EventLoopWindowTarget) { // remove destroyed windows self.windows.retain(|id, _| { - imgui.viewport_by_id(*id).is_some() + imgui.viewports().any(|vp| vp.id == *id) }); // handle new viewports @@ -1051,12 +1051,17 @@ impl WinitPlatform { Event::WindowEvent { window_id, ref event } => { let viewport = { if window_id == main_window.id() { - imgui.main_viewport_mut() + Some(imgui.main_viewport_mut()) } else { - let imgui_id = self.windows.iter().find(|(_, wnd)| wnd.id() == window_id).map(|(id, _)| *id).unwrap(); - imgui.viewport_by_id_mut(imgui_id).unwrap() + self.windows.iter().find(|(_, wnd)| wnd.id() == window_id).map(|(id, _)| *id).and_then(|id| imgui.viewport_by_id_mut(id)) } }; + let viewport = if let Some(viewport) = viewport { + viewport + } else { + return; + }; + let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; match *event { From cb8f63fb8ce91798035bf434636509bee162fbe1 Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Wed, 2 Mar 2022 08:37:53 +0100 Subject: [PATCH 10/42] Fixed initial window positioning and windows not rendering when focused --- imgui-winit-support/src/lib.rs | 37 ++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/imgui-winit-support/src/lib.rs b/imgui-winit-support/src/lib.rs index a975bf6..735d8d2 100644 --- a/imgui-winit-support/src/lib.rs +++ b/imgui-winit-support/src/lib.rs @@ -512,7 +512,7 @@ impl imgui::PlatformViewportBackend for ViewportBackend { fn get_window_minimized(&mut self, viewport: &mut imgui::Viewport) -> bool { let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; - state.focus + state.minimized } fn set_window_title(&mut self, viewport: &mut imgui::Viewport, title: &str) { @@ -666,18 +666,22 @@ impl WinitPlatform { let viewport = imgui.viewport_by_id_mut(*id).unwrap(); let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; - if state.set_show { - wnd.set_visible(true); - state.set_show = false; - } if let Some(pos) = &state.set_pos { - wnd.set_outer_position(winit::dpi::LogicalPosition::new(pos[0], pos[1])); + let wnd_pos = wnd.outer_position().unwrap(); + let inner_pos = wnd.inner_position().unwrap(); + let decoration_size = [inner_pos.x - wnd_pos.x, inner_pos.y - wnd_pos.y]; + + wnd.set_outer_position(winit::dpi::LogicalPosition::new(pos[0] - decoration_size[0] as f32, pos[1] - decoration_size[1] as f32)); state.set_pos = None; } if let Some(size) = &state.set_size { wnd.set_inner_size(winit::dpi::LogicalSize::new(size[0], size[1])); state.set_size = None; } + if state.set_show { + wnd.set_visible(true); + state.set_show = false; + } if state.set_focus { wnd.focus_window(); state.set_focus = false; @@ -1049,6 +1053,17 @@ impl WinitPlatform { pub fn handle_viewport_event(&mut self, imgui: &mut imgui::Context, main_window: &Window, event: &Event) { match *event { Event::WindowEvent { window_id, ref event } => { + let window = if window_id == main_window.id() { + Some(main_window) + } else { + self.windows.iter().find_map(|(_, wnd)| (wnd.id() == window_id).then(|| wnd)) + }; + let window = if let Some(window) = window { + window + } else { + return; + }; + let viewport = { if window_id == main_window.id() { Some(imgui.main_viewport_mut()) @@ -1068,8 +1083,9 @@ impl WinitPlatform { WindowEvent::Resized(new_size) => { state.size = [new_size.width as f32, new_size.height as f32]; }, - WindowEvent::Moved(new_pos) => { - state.pos = [new_pos.x as f32, new_pos.y as f32]; + WindowEvent::Moved(_new_pos) => { + let pos = window.inner_position().unwrap(); + state.pos = [pos.x as f32, pos.y as f32]; }, WindowEvent::CloseRequested => { viewport.platform_request_close = true; @@ -1078,9 +1094,8 @@ impl WinitPlatform { state.focus = focus; }, WindowEvent::CursorMoved { position, .. } => { - let mut pos = state.pos; - pos[0] += position.x as f32; - pos[1] += position.y as f32; + let wnd_pos = window.inner_position().unwrap(); + let pos = [wnd_pos.x as f32 + position.x as f32, wnd_pos.y as f32 + position.y as f32]; imgui.io_mut().mouse_pos = pos; }, WindowEvent::KeyboardInput { From acda14c7f1548830b0422f6cdb38af1ce05f65f2 Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Wed, 2 Mar 2022 10:42:39 +0100 Subject: [PATCH 11/42] Fixed initial window position --- imgui-examples/examples/support/mod.rs | 2 +- imgui-winit-support/src/lib.rs | 16 +++++++++++++--- imgui/src/context.rs | 2 +- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/imgui-examples/examples/support/mod.rs b/imgui-examples/examples/support/mod.rs index aacd200..1424dcd 100644 --- a/imgui-examples/examples/support/mod.rs +++ b/imgui-examples/examples/support/mod.rs @@ -43,7 +43,7 @@ pub fn init(title: &str) -> System { } let mut platform = WinitPlatform::init(&mut imgui); - WinitPlatform::init_viewports(&mut imgui, &event_loop); + WinitPlatform::init_viewports(&mut imgui, display.gl_window().window(), &event_loop); { let gl_window = display.gl_window(); let window = gl_window.window(); diff --git a/imgui-winit-support/src/lib.rs b/imgui-winit-support/src/lib.rs index 735d8d2..02dc30a 100644 --- a/imgui-winit-support/src/lib.rs +++ b/imgui-winit-support/src/lib.rs @@ -600,7 +600,7 @@ impl WinitPlatform { } #[cfg(feature = "viewports")] - pub fn init_viewports(imgui: &mut Context, event_loop: &winit::event_loop::EventLoop) { + pub fn init_viewports(imgui: &mut Context, main_window: &winit::window::Window, event_loop: &winit::event_loop::EventLoop) { let io = imgui.io_mut(); io.backend_flags.insert(BackendFlags::PLATFORM_HAS_VIEWPORTS); @@ -619,6 +619,11 @@ impl WinitPlatform { } imgui.platform_io_mut().monitors.replace_from_slice(&monitors); + let pos = main_window.inner_position().unwrap(); + let pos = [pos.x as f32, pos.y as f32]; + let size = main_window.inner_size(); + let size = [size.width as f32, size.height as f32]; + let main_viewport = imgui.main_viewport_mut(); main_viewport.platform_user_data = Box::into_raw(Box::new(ViewportState { create: false, @@ -628,8 +633,8 @@ impl WinitPlatform { set_size: None, set_focus: false, set_title: None, - pos: [0.0, 0.0], - size: [0.0, 0.0], + pos, + size, focus: true, minimized: false, })) as *mut _; @@ -1082,6 +1087,11 @@ impl WinitPlatform { match *event { WindowEvent::Resized(new_size) => { state.size = [new_size.width as f32, new_size.height as f32]; + if new_size.width == 0 || new_size.height == 0 { + state.minimized = true; + } else { + state.minimized = false; + } }, WindowEvent::Moved(_new_pos) => { let pos = window.inner_position().unwrap(); diff --git a/imgui/src/context.rs b/imgui/src/context.rs index 00d780a..1f843c8 100644 --- a/imgui/src/context.rs +++ b/imgui/src/context.rs @@ -1,6 +1,6 @@ use parking_lot::ReentrantMutex; use std::cell::UnsafeCell; -use std::ffi::{CStr, CString, c_void}; +use std::ffi::{CStr, CString}; use std::ops::Drop; use std::path::PathBuf; use std::ptr::{self, null_mut}; From 07503ff500281433b78fce20509dd9cd95476433 Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Wed, 2 Mar 2022 10:45:22 +0100 Subject: [PATCH 12/42] clippy --- imgui-winit-support/src/lib.rs | 249 ++++++++++++++++----------------- 1 file changed, 123 insertions(+), 126 deletions(-) diff --git a/imgui-winit-support/src/lib.rs b/imgui-winit-support/src/lib.rs index 02dc30a..6955544 100644 --- a/imgui-winit-support/src/lib.rs +++ b/imgui-winit-support/src/lib.rs @@ -1056,134 +1056,131 @@ impl WinitPlatform { } #[cfg(feature = "viewports")] pub fn handle_viewport_event(&mut self, imgui: &mut imgui::Context, main_window: &Window, event: &Event) { - match *event { - Event::WindowEvent { window_id, ref event } => { - let window = if window_id == main_window.id() { - Some(main_window) + if let Event::WindowEvent { window_id, ref event } = *event { + let window = if window_id == main_window.id() { + Some(main_window) + } else { + self.windows.iter().find_map(|(_, wnd)| (wnd.id() == window_id).then(|| wnd)) + }; + let window = if let Some(window) = window { + window + } else { + return; + }; + + let viewport = { + if window_id == main_window.id() { + Some(imgui.main_viewport_mut()) } else { - self.windows.iter().find_map(|(_, wnd)| (wnd.id() == window_id).then(|| wnd)) - }; - let window = if let Some(window) = window { - window - } else { - return; - }; - - let viewport = { - if window_id == main_window.id() { - Some(imgui.main_viewport_mut()) - } else { - self.windows.iter().find(|(_, wnd)| wnd.id() == window_id).map(|(id, _)| *id).and_then(|id| imgui.viewport_by_id_mut(id)) - } - }; - let viewport = if let Some(viewport) = viewport { - viewport - } else { - return; - }; - - let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; - - match *event { - WindowEvent::Resized(new_size) => { - state.size = [new_size.width as f32, new_size.height as f32]; - if new_size.width == 0 || new_size.height == 0 { - state.minimized = true; - } else { - state.minimized = false; - } - }, - WindowEvent::Moved(_new_pos) => { - let pos = window.inner_position().unwrap(); - state.pos = [pos.x as f32, pos.y as f32]; - }, - WindowEvent::CloseRequested => { - viewport.platform_request_close = true; - }, - WindowEvent::Focused(focus) => { - state.focus = focus; - }, - WindowEvent::CursorMoved { position, .. } => { - let wnd_pos = window.inner_position().unwrap(); - let pos = [wnd_pos.x as f32 + position.x as f32, wnd_pos.y as f32 + position.y as f32]; - imgui.io_mut().mouse_pos = pos; - }, - WindowEvent::KeyboardInput { - input: - KeyboardInput { - virtual_keycode: Some(key), - state, - .. - }, - .. - } if window_id != main_window.id() => { - let io = imgui.io_mut(); - - let pressed = state == ElementState::Pressed; - io.keys_down[key as usize] = pressed; - - // This is a bit redundant here, but we'll leave it in. The OS occasionally - // fails to send modifiers keys, but it doesn't seem to send false-positives, - // so double checking isn't terrible in case some system *doesn't* send - // device events sometimes. - match key { - VirtualKeyCode::LShift | VirtualKeyCode::RShift => io.key_shift = pressed, - VirtualKeyCode::LControl | VirtualKeyCode::RControl => io.key_ctrl = pressed, - VirtualKeyCode::LAlt | VirtualKeyCode::RAlt => io.key_alt = pressed, - VirtualKeyCode::LWin | VirtualKeyCode::RWin => io.key_super = pressed, - _ => (), - } - }, - WindowEvent::ReceivedCharacter(ch) if window_id != main_window.id() => { - let io = imgui.io_mut(); - - // Exclude the backspace key ('\u{7f}'). Otherwise we will insert this char and then - // delete it. - if ch != '\u{7f}' { - io.add_input_character(ch) - } - }, - WindowEvent::MouseWheel { - delta, - phase: TouchPhase::Moved, - .. - } if window_id != main_window.id() => match delta { - MouseScrollDelta::LineDelta(h, v) => { - let io = imgui.io_mut(); - io.mouse_wheel_h = h; - io.mouse_wheel = v; - } - MouseScrollDelta::PixelDelta(pos) => { - let io = imgui.io_mut(); - let pos = pos.to_logical::(self.hidpi_factor); - match pos.x.partial_cmp(&0.0) { - Some(Ordering::Greater) => io.mouse_wheel_h += 1.0, - Some(Ordering::Less) => io.mouse_wheel_h -= 1.0, - _ => (), - } - match pos.y.partial_cmp(&0.0) { - Some(Ordering::Greater) => io.mouse_wheel += 1.0, - Some(Ordering::Less) => io.mouse_wheel -= 1.0, - _ => (), - } - } - }, - WindowEvent::MouseInput { state, button, .. } if window_id != main_window.id() => { - let pressed = state == ElementState::Pressed; - match button { - MouseButton::Left => self.mouse_buttons[0].set(pressed), - MouseButton::Right => self.mouse_buttons[1].set(pressed), - MouseButton::Middle => self.mouse_buttons[2].set(pressed), - MouseButton::Other(idx @ 0..=4) => { - self.mouse_buttons[idx as usize].set(pressed) - } - _ => (), - } - }, - _ => {}, + self.windows.iter().find(|(_, wnd)| wnd.id() == window_id).map(|(id, _)| *id).and_then(|id| imgui.viewport_by_id_mut(id)) } - }, - _ => {}, + }; + let viewport = if let Some(viewport) = viewport { + viewport + } else { + return; + }; + + let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + + match *event { + WindowEvent::Resized(new_size) => { + state.size = [new_size.width as f32, new_size.height as f32]; + if new_size.width == 0 || new_size.height == 0 { + state.minimized = true; + } else { + state.minimized = false; + } + }, + WindowEvent::Moved(_new_pos) => { + let pos = window.inner_position().unwrap(); + state.pos = [pos.x as f32, pos.y as f32]; + }, + WindowEvent::CloseRequested => { + viewport.platform_request_close = true; + }, + WindowEvent::Focused(focus) => { + state.focus = focus; + }, + WindowEvent::CursorMoved { position, .. } => { + let wnd_pos = window.inner_position().unwrap(); + let pos = [wnd_pos.x as f32 + position.x as f32, wnd_pos.y as f32 + position.y as f32]; + imgui.io_mut().mouse_pos = pos; + }, + WindowEvent::KeyboardInput { + input: + KeyboardInput { + virtual_keycode: Some(key), + state, + .. + }, + .. + } if window_id != main_window.id() => { + let io = imgui.io_mut(); + + let pressed = state == ElementState::Pressed; + io.keys_down[key as usize] = pressed; + + // This is a bit redundant here, but we'll leave it in. The OS occasionally + // fails to send modifiers keys, but it doesn't seem to send false-positives, + // so double checking isn't terrible in case some system *doesn't* send + // device events sometimes. + match key { + VirtualKeyCode::LShift | VirtualKeyCode::RShift => io.key_shift = pressed, + VirtualKeyCode::LControl | VirtualKeyCode::RControl => io.key_ctrl = pressed, + VirtualKeyCode::LAlt | VirtualKeyCode::RAlt => io.key_alt = pressed, + VirtualKeyCode::LWin | VirtualKeyCode::RWin => io.key_super = pressed, + _ => (), + } + }, + WindowEvent::ReceivedCharacter(ch) if window_id != main_window.id() => { + let io = imgui.io_mut(); + + // Exclude the backspace key ('\u{7f}'). Otherwise we will insert this char and then + // delete it. + if ch != '\u{7f}' { + io.add_input_character(ch) + } + }, + WindowEvent::MouseWheel { + delta, + phase: TouchPhase::Moved, + .. + } if window_id != main_window.id() => match delta { + MouseScrollDelta::LineDelta(h, v) => { + let io = imgui.io_mut(); + io.mouse_wheel_h = h; + io.mouse_wheel = v; + } + MouseScrollDelta::PixelDelta(pos) => { + let io = imgui.io_mut(); + let pos = pos.to_logical::(self.hidpi_factor); + match pos.x.partial_cmp(&0.0) { + Some(Ordering::Greater) => io.mouse_wheel_h += 1.0, + Some(Ordering::Less) => io.mouse_wheel_h -= 1.0, + _ => (), + } + match pos.y.partial_cmp(&0.0) { + Some(Ordering::Greater) => io.mouse_wheel += 1.0, + Some(Ordering::Less) => io.mouse_wheel -= 1.0, + _ => (), + } + } + }, + WindowEvent::MouseInput { state, button, .. } if window_id != main_window.id() => { + let pressed = state == ElementState::Pressed; + match button { + MouseButton::Left => self.mouse_buttons[0].set(pressed), + MouseButton::Right => self.mouse_buttons[1].set(pressed), + MouseButton::Middle => self.mouse_buttons[2].set(pressed), + MouseButton::Other(idx @ 0..=4) => { + self.mouse_buttons[idx as usize].set(pressed) + } + _ => (), + } + }, + _ => {}, + } } } From 066d802979e52edefd5921d6b71d519b18fffcef Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Fri, 4 Mar 2022 13:09:59 +0100 Subject: [PATCH 13/42] Make sure imgui compiles with docking enabled and disabled --- imgui/src/context.rs | 239 +++++++++++++++++++++------------------ imgui/src/internal.rs | 2 +- imgui/src/io.rs | 4 +- imgui/src/lib.rs | 6 +- imgui/src/platform_io.rs | 168 ++++++++++++++++++--------- 5 files changed, 251 insertions(+), 168 deletions(-) diff --git a/imgui/src/context.rs b/imgui/src/context.rs index 1f843c8..75d018d 100644 --- a/imgui/src/context.rs +++ b/imgui/src/context.rs @@ -3,13 +3,13 @@ use std::cell::UnsafeCell; use std::ffi::{CStr, CString}; use std::ops::Drop; use std::path::PathBuf; -use std::ptr::{self, null_mut}; +use std::ptr; use crate::clipboard::{ClipboardBackend, ClipboardContext}; use crate::fonts::atlas::{FontAtlas, FontId, SharedFontAtlas}; use crate::io::Io; use crate::style::Style; -use crate::{sys, DrawData, PlatformIo, PlatformViewportContext, RendererViewportContext, PlatformViewportBackend, RendererViewportBackend, Viewport, Id}; +use crate::{sys, DrawData}; use crate::{MouseCursor, Ui}; /// An imgui-rs context. @@ -60,8 +60,10 @@ pub struct Context { // imgui a mutable pointer to it. clipboard_ctx: Box>, - platform_viewport_ctx: Box>, - renderer_viewport_ctx: Box>, + #[cfg(feature = "docking")] + platform_viewport_ctx: Box>, + #[cfg(feature = "docking")] + renderer_viewport_ctx: Box>, ui: Ui, } @@ -219,67 +221,6 @@ impl Context { io.clipboard_user_data = clipboard_ctx.get() as *mut _; self.clipboard_ctx = clipboard_ctx; } - pub fn set_platform_backend(&mut self, backend: T) { - let ctx = Box::new(UnsafeCell::new(PlatformViewportContext { - backend: Box::new(backend), - })); - - let io = self.io_mut(); - io.backend_platform_user_data = ctx.get() as *mut _; - - let pio = self.platform_io_mut(); - pio.platform_create_window = Some(crate::platform_io::platform_create_window); - pio.platform_destroy_window = Some(crate::platform_io::platform_destroy_window); - pio.platform_show_window = Some(crate::platform_io::platform_show_window); - pio.platform_set_window_pos = Some(crate::platform_io::platform_set_window_pos); - // pio.platform_get_window_pos = Some(crate::platform_io::platform_get_window_pos); - unsafe { - crate::platform_io::ImGuiPlatformIO_Set_Platform_GetWindowPos(pio, crate::platform_io::platform_get_window_pos); - } - pio.platform_set_window_size = Some(crate::platform_io::platform_set_window_size); - // pio.platform_get_window_size = Some(crate::platform_io::platform_get_window_size); - unsafe { - crate::platform_io::ImGuiPlatformIO_Set_Platform_GetWindowSize(pio, crate::platform_io::platform_get_window_size); - } - pio.platform_set_window_focus = Some(crate::platform_io::platform_set_window_focus); - pio.platform_get_window_focus = Some(crate::platform_io::platform_get_window_focus); - pio.platform_get_window_minimized = Some(crate::platform_io::platform_get_window_minimized); - pio.platform_set_window_title = Some(crate::platform_io::platform_set_window_title); - pio.platform_set_window_alpha = Some(crate::platform_io::platform_set_window_alpha); - pio.platform_update_window = Some(crate::platform_io::platform_update_window); - pio.platform_render_window = Some(crate::platform_io::platform_render_window); - pio.platform_swap_buffers = Some(crate::platform_io::platform_swap_buffers); - pio.platform_create_vk_surface = Some(crate::platform_io::platform_create_vk_surface); - - self.platform_viewport_ctx = ctx; - } - pub fn set_renderer_backend(&mut self, backend: T) { - let ctx = Box::new(UnsafeCell::new(RendererViewportContext { - backend: Box::new(backend), - })); - - let io = self.io_mut(); - io.backend_renderer_user_data = ctx.get() as *mut _; - - let pio = self.platform_io_mut(); - pio.renderer_create_window = Some(crate::platform_io::renderer_create_window); - pio.renderer_destroy_window = Some(crate::platform_io::renderer_destroy_window); - pio.renderer_set_window_size = Some(crate::platform_io::renderer_set_window_size); - pio.renderer_render_window = Some(crate::platform_io::renderer_render_window); - pio.renderer_swap_buffers = Some(crate::platform_io::renderer_swap_buffers); - - self.renderer_viewport_ctx = ctx; - } - pub fn update_platform_windows(&mut self) { - unsafe { - sys::igUpdatePlatformWindows(); - } - } - pub fn render_platform_windows_default(&mut self) { - unsafe { - sys::igRenderPlatformWindowsDefault(null_mut(), null_mut()); - } - } fn create_internal(mut shared_font_atlas: Option) -> Self { let _guard = CTX_MUTEX.lock(); assert!( @@ -303,8 +244,14 @@ impl Context { platform_name: None, renderer_name: None, clipboard_ctx: Box::new(ClipboardContext::dummy().into()), - platform_viewport_ctx: Box::new(UnsafeCell::new(PlatformViewportContext::dummy())), - renderer_viewport_ctx: Box::new(UnsafeCell::new(RendererViewportContext::dummy())), + #[cfg(feature = "docking")] + platform_viewport_ctx: Box::new(UnsafeCell::new( + crate::PlatformViewportContext::dummy(), + )), + #[cfg(feature = "docking")] + renderer_viewport_ctx: Box::new(UnsafeCell::new( + crate::RendererViewportContext::dummy(), + )), ui: Ui { buffer: UnsafeCell::new(crate::string::UiBuffer::new(1024)), }, @@ -394,8 +341,14 @@ impl SuspendedContext { platform_name: None, renderer_name: None, clipboard_ctx: Box::new(ClipboardContext::dummy().into()), - platform_viewport_ctx: Box::new(UnsafeCell::new(PlatformViewportContext::dummy())), - renderer_viewport_ctx: Box::new(UnsafeCell::new(RendererViewportContext::dummy())), + #[cfg(feature = "docking")] + platform_viewport_ctx: Box::new(UnsafeCell::new( + crate::PlatformViewportContext::dummy(), + )), + #[cfg(feature = "docking")] + renderer_viewport_ctx: Box::new(UnsafeCell::new( + crate::RendererViewportContext::dummy(), + )), ui: Ui { buffer: UnsafeCell::new(crate::string::UiBuffer::new(1024)), }, @@ -547,50 +500,6 @@ impl Context { &mut *(sys::igGetIO() as *mut Io) } } - pub fn platform_io(&self) -> &PlatformIo { - unsafe { - // safe because PlatformIo is a transparent wrapper around sys::ImGuiPlatformIO - &*(sys::igGetPlatformIO() as *const PlatformIo) - } - } - pub fn platform_io_mut(&mut self) -> &mut PlatformIo { - unsafe { - // safe because PlatformIo is a transparent wrapper around sys::ImGuiPlatformIO - &mut *(sys::igGetPlatformIO() as *mut PlatformIo) - } - } - pub fn main_viewport(&self) -> &Viewport { - unsafe { - &*(sys::igGetMainViewport() as *mut Viewport) - } - } - pub fn main_viewport_mut(&mut self) -> &mut Viewport { - unsafe { - &mut *(sys::igGetMainViewport() as *mut Viewport) - } - } - pub fn viewport_by_id(&self, id: Id) -> Option<&Viewport> { - unsafe { - (sys::igFindViewportByID(id.0) as *const Viewport).as_ref() - } - } - pub fn viewport_by_id_mut(&mut self, id: Id) -> Option<&mut Viewport> { - unsafe { - (sys::igFindViewportByID(id.0) as *mut Viewport).as_mut() - } - } - pub fn viewports(&self) -> impl Iterator { - let slice = self.platform_io().viewports.as_slice(); - unsafe { - slice.iter().map(|ptr| &**ptr) - } - } - pub fn viewports_mut(&mut self) -> impl Iterator { - let slice = self.platform_io_mut().viewports.as_slice(); - unsafe { - slice.iter().map(|ptr| &mut **ptr) - } - } /// Returns an immutable reference to the user interface style #[doc(alias = "GetStyle")] pub fn style(&self) -> &Style { @@ -680,3 +589,107 @@ impl Context { } } } + +#[cfg(feature = "docking")] +impl Context { + pub fn platform_io(&self) -> &crate::PlatformIo { + unsafe { + // safe because PlatformIo is a transparent wrapper around sys::ImGuiPlatformIO + &*(sys::igGetPlatformIO() as *const crate::PlatformIo) + } + } + pub fn platform_io_mut(&mut self) -> &mut crate::PlatformIo { + unsafe { + // safe because PlatformIo is a transparent wrapper around sys::ImGuiPlatformIO + &mut *(sys::igGetPlatformIO() as *mut crate::PlatformIo) + } + } + pub fn main_viewport(&self) -> &crate::Viewport { + unsafe { &*(sys::igGetMainViewport() as *mut crate::Viewport) } + } + pub fn main_viewport_mut(&mut self) -> &mut crate::Viewport { + unsafe { &mut *(sys::igGetMainViewport() as *mut crate::Viewport) } + } + pub fn viewport_by_id(&self, id: crate::Id) -> Option<&crate::Viewport> { + unsafe { (sys::igFindViewportByID(id.0) as *const crate::Viewport).as_ref() } + } + pub fn viewport_by_id_mut(&mut self, id: crate::Id) -> Option<&mut crate::Viewport> { + unsafe { (sys::igFindViewportByID(id.0) as *mut crate::Viewport).as_mut() } + } + pub fn viewports(&self) -> impl Iterator { + let slice = self.platform_io().viewports.as_slice(); + unsafe { slice.iter().map(|ptr| &**ptr) } + } + pub fn viewports_mut(&mut self) -> impl Iterator { + let slice = self.platform_io_mut().viewports.as_slice(); + unsafe { slice.iter().map(|ptr| &mut **ptr) } + } + + pub fn set_platform_backend(&mut self, backend: T) { + let ctx = Box::new(UnsafeCell::new(crate::PlatformViewportContext { + backend: Box::new(backend), + })); + + let io = self.io_mut(); + io.backend_platform_user_data = ctx.get() as *mut _; + + let pio = self.platform_io_mut(); + pio.platform_create_window = Some(crate::platform_io::platform_create_window); + pio.platform_destroy_window = Some(crate::platform_io::platform_destroy_window); + pio.platform_show_window = Some(crate::platform_io::platform_show_window); + pio.platform_set_window_pos = Some(crate::platform_io::platform_set_window_pos); + // pio.platform_get_window_pos = Some(crate::platform_io::platform_get_window_pos); + unsafe { + crate::platform_io::ImGuiPlatformIO_Set_Platform_GetWindowPos( + pio, + crate::platform_io::platform_get_window_pos, + ); + } + pio.platform_set_window_size = Some(crate::platform_io::platform_set_window_size); + // pio.platform_get_window_size = Some(crate::platform_io::platform_get_window_size); + unsafe { + crate::platform_io::ImGuiPlatformIO_Set_Platform_GetWindowSize( + pio, + crate::platform_io::platform_get_window_size, + ); + } + pio.platform_set_window_focus = Some(crate::platform_io::platform_set_window_focus); + pio.platform_get_window_focus = Some(crate::platform_io::platform_get_window_focus); + pio.platform_get_window_minimized = Some(crate::platform_io::platform_get_window_minimized); + pio.platform_set_window_title = Some(crate::platform_io::platform_set_window_title); + pio.platform_set_window_alpha = Some(crate::platform_io::platform_set_window_alpha); + pio.platform_update_window = Some(crate::platform_io::platform_update_window); + pio.platform_render_window = Some(crate::platform_io::platform_render_window); + pio.platform_swap_buffers = Some(crate::platform_io::platform_swap_buffers); + pio.platform_create_vk_surface = Some(crate::platform_io::platform_create_vk_surface); + + self.platform_viewport_ctx = ctx; + } + pub fn set_renderer_backend(&mut self, backend: T) { + let ctx = Box::new(UnsafeCell::new(crate::RendererViewportContext { + backend: Box::new(backend), + })); + + let io = self.io_mut(); + io.backend_renderer_user_data = ctx.get() as *mut _; + + let pio = self.platform_io_mut(); + pio.renderer_create_window = Some(crate::platform_io::renderer_create_window); + pio.renderer_destroy_window = Some(crate::platform_io::renderer_destroy_window); + pio.renderer_set_window_size = Some(crate::platform_io::renderer_set_window_size); + pio.renderer_render_window = Some(crate::platform_io::renderer_render_window); + pio.renderer_swap_buffers = Some(crate::platform_io::renderer_swap_buffers); + + self.renderer_viewport_ctx = ctx; + } + pub fn update_platform_windows(&mut self) { + unsafe { + sys::igUpdatePlatformWindows(); + } + } + pub fn render_platform_windows_default(&mut self) { + unsafe { + sys::igRenderPlatformWindowsDefault(std::ptr::null_mut(), std::ptr::null_mut()); + } + } +} diff --git a/imgui/src/internal.rs b/imgui/src/internal.rs index d7869a3..7116cda 100644 --- a/imgui/src/internal.rs +++ b/imgui/src/internal.rs @@ -1,6 +1,6 @@ //! Internal raw utilities (don't use unless you know what you're doing!) -use std::{slice, mem::size_of}; +use std::{mem::size_of, slice}; /// A generic version of the raw imgui-sys ImVector struct types #[repr(C)] diff --git a/imgui/src/io.rs b/imgui/src/io.rs index 7681ed8..46f933a 100644 --- a/imgui/src/io.rs +++ b/imgui/src/io.rs @@ -59,8 +59,10 @@ bitflags! { #[cfg(feature = "docking")] const VIEWPORTS_ENABLE = sys::ImGuiConfigFlags_ViewportsEnable; } +} - #[cfg(feature = "docking")] +#[cfg(feature = "docking")] +bitflags! { #[repr(transparent)] pub struct ViewportFlags: u32 { const IS_PLATFORM_WINDOW = sys::ImGuiViewportFlags_IsPlatformWindow; diff --git a/imgui/src/lib.rs b/imgui/src/lib.rs index 6958686..5edb9a2 100644 --- a/imgui/src/lib.rs +++ b/imgui/src/lib.rs @@ -20,9 +20,10 @@ pub use self::input::keyboard::*; pub use self::input::mouse::*; pub use self::input_widget::*; pub use self::io::*; -pub use self::platform_io::*; pub use self::layout::*; pub use self::list_clipper::ListClipper; +#[cfg(feature = "docking")] +pub use self::platform_io::*; pub use self::plothistogram::PlotHistogram; pub use self::plotlines::PlotLines; pub use self::popups::*; @@ -69,10 +70,11 @@ mod input; mod input_widget; pub mod internal; mod io; -mod platform_io; mod layout; mod list_clipper; mod math; +#[cfg(feature = "docking")] +mod platform_io; mod plothistogram; mod plotlines; mod popups; diff --git a/imgui/src/platform_io.rs b/imgui/src/platform_io.rs index 9e0c696..889cbf8 100644 --- a/imgui/src/platform_io.rs +++ b/imgui/src/platform_io.rs @@ -1,8 +1,13 @@ -use std::{os::raw::{c_char, c_int}, ffi::{c_void, CStr}}; +use std::{ + ffi::{c_void, CStr}, + os::raw::{c_char, c_int}, +}; -use crate::{internal::{ImVector, RawCast}, ViewportFlags, Io}; +use crate::{ + internal::{ImVector, RawCast}, + Io, ViewportFlags, +}; -#[cfg(feature = "docking")] #[repr(C)] pub struct PlatformIo { pub(crate) platform_create_window: Option, @@ -15,7 +20,8 @@ pub struct PlatformIo { pub(crate) platform_set_window_focus: Option, pub(crate) platform_get_window_focus: Option bool>, pub(crate) platform_get_window_minimized: Option bool>, - pub(crate) platform_set_window_title: Option, + pub(crate) platform_set_window_title: + Option, pub(crate) platform_set_window_alpha: Option, pub(crate) platform_update_window: Option, pub(crate) platform_render_window: Option, @@ -23,7 +29,8 @@ pub struct PlatformIo { pub(crate) platform_get_window_dpi_scale: Option f32>, pub(crate) platform_on_changed_viewport: Option, pub(crate) platform_set_ime_input_pos: Option, - pub(crate) platform_create_vk_surface: Option c_int>, + pub(crate) platform_create_vk_surface: + Option c_int>, pub(crate) renderer_create_window: Option, pub(crate) renderer_destroy_window: Option, @@ -42,8 +49,14 @@ unsafe impl RawCast for PlatformIo {} #[cfg(test)] fn test_platform_io_memory_layout() { use std::mem; - assert_eq!(mem::size_of::(), mem::size_of::()); - assert_eq!(mem::align_of::(), mem::align_of::()); + assert_eq!( + mem::size_of::(), + mem::size_of::() + ); + assert_eq!( + mem::align_of::(), + mem::align_of::() + ); use sys::ImGuiPlatformIO; macro_rules! assert_field_offset { ($l:ident, $r:ident) => { @@ -101,91 +114,116 @@ pub trait PlatformViewportBackend: 'static { fn update_window(&mut self, viewport: &mut Viewport); fn render_window(&mut self, viewport: &mut Viewport); fn swap_buffers(&mut self, viewport: &mut Viewport); - fn create_vk_surface(&mut self, viewport: &mut Viewport, instance: u64, out_surface: &mut u64) -> i32; + fn create_vk_surface( + &mut self, + viewport: &mut Viewport, + instance: u64, + out_surface: &mut u64, + ) -> i32; } fn get_platform_ctx() -> &'static mut PlatformViewportContext { unsafe { - &mut *((*(sys::igGetIO() as *const Io)).backend_platform_user_data as *mut PlatformViewportContext) + &mut *((*(sys::igGetIO() as *const Io)).backend_platform_user_data + as *mut PlatformViewportContext) } } fn get_renderer_ctx() -> &'static mut RendererViewportContext { unsafe { - &mut *((*(sys::igGetIO() as *const Io)).backend_platform_user_data as *mut RendererViewportContext) + &mut *((*(sys::igGetIO() as *const Io)).backend_platform_user_data + as *mut RendererViewportContext) } } pub(crate) extern "C" fn platform_create_window(viewport: *mut Viewport) { let ctx = get_platform_ctx(); - ctx.backend.create_window(unsafe{&mut *viewport}); + ctx.backend.create_window(unsafe { &mut *viewport }); } pub(crate) extern "C" fn platform_destroy_window(viewport: *mut Viewport) { let ctx = get_platform_ctx(); - ctx.backend.destroy_window(unsafe{&mut *viewport}); + ctx.backend.destroy_window(unsafe { &mut *viewport }); } pub(crate) extern "C" fn platform_show_window(viewport: *mut Viewport) { let ctx = get_platform_ctx(); - ctx.backend.show_window(unsafe{&mut *viewport}); + ctx.backend.show_window(unsafe { &mut *viewport }); } pub(crate) extern "C" fn platform_set_window_pos(viewport: *mut Viewport, pos: sys::ImVec2) { let ctx = get_platform_ctx(); - ctx.backend.set_window_pos(unsafe{&mut *viewport}, [pos.x, pos.y]); + ctx.backend + .set_window_pos(unsafe { &mut *viewport }, [pos.x, pos.y]); } -pub(crate) extern "C" fn platform_get_window_pos(viewport: *mut Viewport, out_pos: *mut sys::ImVec2) { +pub(crate) extern "C" fn platform_get_window_pos( + viewport: *mut Viewport, + out_pos: *mut sys::ImVec2, +) { let ctx = get_platform_ctx(); - let pos = ctx.backend.get_window_pos(unsafe{&mut *viewport}); + let pos = ctx.backend.get_window_pos(unsafe { &mut *viewport }); unsafe { *out_pos = sys::ImVec2::new(pos[0], pos[1]); } } pub(crate) extern "C" fn platform_set_window_size(viewport: *mut Viewport, size: sys::ImVec2) { let ctx = get_platform_ctx(); - ctx.backend.set_window_size(unsafe{&mut *viewport}, [size.x, size.y]); + ctx.backend + .set_window_size(unsafe { &mut *viewport }, [size.x, size.y]); } -pub(crate) extern "C" fn platform_get_window_size(viewport: *mut Viewport, out_size: *mut sys::ImVec2) { +pub(crate) extern "C" fn platform_get_window_size( + viewport: *mut Viewport, + out_size: *mut sys::ImVec2, +) { let ctx = get_platform_ctx(); - let size = ctx.backend.get_window_size(unsafe{&mut *viewport}); + let size = ctx.backend.get_window_size(unsafe { &mut *viewport }); unsafe { *out_size = sys::ImVec2::new(size[0], size[1]); } } pub(crate) extern "C" fn platform_set_window_focus(viewport: *mut Viewport) { let ctx = get_platform_ctx(); - ctx.backend.set_window_focus(unsafe{&mut *viewport}); + ctx.backend.set_window_focus(unsafe { &mut *viewport }); } pub(crate) extern "C" fn platform_get_window_focus(viewport: *mut Viewport) -> bool { let ctx = get_platform_ctx(); - ctx.backend.get_window_focus(unsafe{&mut *viewport}) + ctx.backend.get_window_focus(unsafe { &mut *viewport }) } pub(crate) extern "C" fn platform_get_window_minimized(viewport: *mut Viewport) -> bool { let ctx = get_platform_ctx(); - ctx.backend.get_window_minimized(unsafe{&mut *viewport}) + ctx.backend.get_window_minimized(unsafe { &mut *viewport }) } pub(crate) extern "C" fn platform_set_window_title(viewport: *mut Viewport, title: *const c_char) { let ctx = get_platform_ctx(); let title = unsafe { CStr::from_ptr(title).to_str().unwrap() }; - ctx.backend.set_window_title(unsafe{&mut *viewport}, title); + ctx.backend + .set_window_title(unsafe { &mut *viewport }, title); } pub(crate) extern "C" fn platform_set_window_alpha(viewport: *mut Viewport, alpha: f32) { let ctx = get_platform_ctx(); - ctx.backend.set_window_alpha(unsafe{&mut *viewport}, alpha); + ctx.backend + .set_window_alpha(unsafe { &mut *viewport }, alpha); } pub(crate) extern "C" fn platform_update_window(viewport: *mut Viewport) { let ctx = get_platform_ctx(); - ctx.backend.update_window(unsafe{&mut *viewport}); + ctx.backend.update_window(unsafe { &mut *viewport }); } pub(crate) extern "C" fn platform_render_window(viewport: *mut Viewport, _arg: *mut c_void) { let ctx = get_platform_ctx(); - ctx.backend.render_window(unsafe{&mut *viewport}); + ctx.backend.render_window(unsafe { &mut *viewport }); } pub(crate) extern "C" fn platform_swap_buffers(viewport: *mut Viewport, _arg: *mut c_void) { let ctx = get_platform_ctx(); - ctx.backend.swap_buffers(unsafe{&mut *viewport}); + ctx.backend.swap_buffers(unsafe { &mut *viewport }); } -pub(crate) extern "C" fn platform_create_vk_surface(viewport: *mut Viewport, instance: u64, _arg: *const c_void, out_surface: *mut u64) -> c_int { +pub(crate) extern "C" fn platform_create_vk_surface( + viewport: *mut Viewport, + instance: u64, + _arg: *const c_void, + out_surface: *mut u64, +) -> c_int { let ctx = get_platform_ctx(); - ctx.backend.create_vk_surface(unsafe{&mut *viewport}, instance, unsafe{&mut *out_surface}) + ctx.backend + .create_vk_surface(unsafe { &mut *viewport }, instance, unsafe { + &mut *out_surface + }) } pub(crate) struct DummyPlatformViewportBackend {} @@ -250,7 +288,12 @@ impl PlatformViewportBackend for DummyPlatformViewportBackend { unimplemented!() } - fn create_vk_surface(&mut self, _viewport: &mut Viewport, _instance: u64, _out_surface: &mut u64) -> i32 { + fn create_vk_surface( + &mut self, + _viewport: &mut Viewport, + _instance: u64, + _out_surface: &mut u64, + ) -> i32 { unimplemented!() } } @@ -262,7 +305,7 @@ pub(crate) struct PlatformViewportContext { impl PlatformViewportContext { pub(crate) fn dummy() -> Self { Self { - backend: Box::new(DummyPlatformViewportBackend{}), + backend: Box::new(DummyPlatformViewportBackend {}), } } } @@ -277,23 +320,24 @@ pub trait RendererViewportBackend: 'static { pub(crate) extern "C" fn renderer_create_window(viewport: *mut Viewport) { let ctx = get_renderer_ctx(); - ctx.backend.create_window(unsafe{&mut *viewport}); + ctx.backend.create_window(unsafe { &mut *viewport }); } pub(crate) extern "C" fn renderer_destroy_window(viewport: *mut Viewport) { let ctx = get_renderer_ctx(); - ctx.backend.destroy_window(unsafe{&mut *viewport}); + ctx.backend.destroy_window(unsafe { &mut *viewport }); } pub(crate) extern "C" fn renderer_set_window_size(viewport: *mut Viewport, size: sys::ImVec2) { let ctx = get_renderer_ctx(); - ctx.backend.set_window_size(unsafe{&mut *viewport}, [size.x, size.y]); + ctx.backend + .set_window_size(unsafe { &mut *viewport }, [size.x, size.y]); } pub(crate) extern "C" fn renderer_render_window(viewport: *mut Viewport, _arg: *mut c_void) { let ctx = get_renderer_ctx(); - ctx.backend.render_window(unsafe{&mut *viewport}); + ctx.backend.render_window(unsafe { &mut *viewport }); } pub(crate) extern "C" fn renderer_swap_buffers(viewport: *mut Viewport, _arg: *mut c_void) { let ctx = get_renderer_ctx(); - ctx.backend.swap_buffers(unsafe{&mut *viewport}); + ctx.backend.swap_buffers(unsafe { &mut *viewport }); } pub(crate) struct DummyRendererViewportBackend {} @@ -326,24 +370,23 @@ pub(crate) struct RendererViewportContext { impl RendererViewportContext { pub(crate) fn dummy() -> Self { Self { - backend: Box::new(DummyRendererViewportBackend{}), + backend: Box::new(DummyRendererViewportBackend {}), } } } -#[cfg(feature = "docking")] #[repr(C)] pub struct Viewport { pub id: crate::Id, pub flags: ViewportFlags, - pub(crate) pos: [f32; 2], - pub(crate) size: [f32; 2], - pub(crate) work_pos: [f32; 2], - pub(crate) work_size: [f32; 2], - pub(crate) dpi_scale: f32, + pub pos: [f32; 2], + pub size: [f32; 2], + pub work_pos: [f32; 2], + pub work_size: [f32; 2], + pub dpi_scale: f32, pub(crate) parent_viewport_id: crate::Id, pub(crate) draw_data: *mut crate::DrawData, - + pub renderer_user_data: *mut c_void, pub platform_user_data: *mut c_void, pub platform_handle: *mut c_void, @@ -353,12 +396,24 @@ pub struct Viewport { pub platform_request_close: bool, } +impl Viewport { + pub fn draw_data(&self) -> &crate::DrawData { + unsafe { &*self.draw_data } + } +} + #[test] #[cfg(test)] fn test_viewport_memory_layout() { use std::mem; - assert_eq!(mem::size_of::(), mem::size_of::()); - assert_eq!(mem::align_of::(), mem::align_of::()); + assert_eq!( + mem::size_of::(), + mem::size_of::() + ); + assert_eq!( + mem::align_of::(), + mem::align_of::() + ); use sys::ImGuiViewport; macro_rules! assert_field_offset { ($l:ident, $r:ident) => { @@ -388,7 +443,6 @@ fn test_viewport_memory_layout() { assert_field_offset!(platform_request_close, PlatformRequestClose); } -#[cfg(feature = "docking")] #[repr(C)] pub struct PlatformMonitor { pub main_pos: [f32; 2], @@ -402,8 +456,14 @@ pub struct PlatformMonitor { #[cfg(test)] fn test_platform_monitor_memory_layout() { use std::mem; - assert_eq!(mem::size_of::(), mem::size_of::()); - assert_eq!(mem::align_of::(), mem::align_of::()); + assert_eq!( + mem::size_of::(), + mem::size_of::() + ); + assert_eq!( + mem::align_of::(), + mem::align_of::() + ); use sys::ImGuiPlatformMonitor; macro_rules! assert_field_offset { ($l:ident, $r:ident) => { @@ -422,6 +482,12 @@ fn test_platform_monitor_memory_layout() { } extern "C" { - pub(crate) fn ImGuiPlatformIO_Set_Platform_GetWindowPos(pio: *mut PlatformIo, func: extern "C" fn(*mut Viewport, *mut sys::ImVec2)); - pub(crate) fn ImGuiPlatformIO_Set_Platform_GetWindowSize(pio: *mut PlatformIo, func: extern "C" fn(*mut Viewport, *mut sys::ImVec2)); + pub(crate) fn ImGuiPlatformIO_Set_Platform_GetWindowPos( + pio: *mut PlatformIo, + func: extern "C" fn(*mut Viewport, *mut sys::ImVec2), + ); + pub(crate) fn ImGuiPlatformIO_Set_Platform_GetWindowSize( + pio: *mut PlatformIo, + func: extern "C" fn(*mut Viewport, *mut sys::ImVec2), + ); } From c2644cb0bedf8168930636531dd3b5b32c1fe996 Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Fri, 4 Mar 2022 13:10:43 +0100 Subject: [PATCH 14/42] imgui-winit-support now uses external storage for extra windows --- imgui-winit-support/src/lib.rs | 171 ++++++++++++++++++--------------- 1 file changed, 96 insertions(+), 75 deletions(-) diff --git a/imgui-winit-support/src/lib.rs b/imgui-winit-support/src/lib.rs index 6955544..a7a14b6 100644 --- a/imgui-winit-support/src/lib.rs +++ b/imgui-winit-support/src/lib.rs @@ -189,8 +189,8 @@ use winit_20 as winit; use winit_19 as winit; use imgui::{self, BackendFlags, ConfigFlags, Context, Io, Key, Ui}; -use std::{cell::Cell, collections::HashMap}; use std::cmp::Ordering; +use std::{cell::Cell, collections::HashMap}; use winit::dpi::{LogicalPosition, LogicalSize}; #[cfg(all( @@ -342,9 +342,6 @@ pub struct WinitPlatform { hidpi_factor: f64, cursor_cache: Option, mouse_buttons: [Button; 5], - - #[cfg(feature = "viewports")] - windows: HashMap, } #[derive(Debug, Copy, Clone, Eq, PartialEq)] @@ -476,47 +473,47 @@ impl imgui::PlatformViewportBackend for ViewportBackend { } fn show_window(&mut self, viewport: &mut imgui::Viewport) { - let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; state.set_show = true; } fn set_window_pos(&mut self, viewport: &mut imgui::Viewport, pos: [f32; 2]) { - let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; state.set_pos = Some(pos); } fn get_window_pos(&mut self, viewport: &mut imgui::Viewport) -> [f32; 2] { - let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; state.pos } fn set_window_size(&mut self, viewport: &mut imgui::Viewport, size: [f32; 2]) { - let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; state.set_size = Some(size); } fn get_window_size(&mut self, viewport: &mut imgui::Viewport) -> [f32; 2] { - let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; state.size } fn set_window_focus(&mut self, viewport: &mut imgui::Viewport) { - let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; state.set_focus = true; } fn get_window_focus(&mut self, viewport: &mut imgui::Viewport) -> bool { - let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; state.focus } fn get_window_minimized(&mut self, viewport: &mut imgui::Viewport) -> bool { - let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; state.minimized } fn set_window_title(&mut self, viewport: &mut imgui::Viewport, title: &str) { - let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; state.set_title = Some(title.to_string()); } @@ -528,7 +525,14 @@ impl imgui::PlatformViewportBackend for ViewportBackend { fn swap_buffers(&mut self, _viewport: &mut imgui::Viewport) {} - fn create_vk_surface(&mut self, _viewport: &mut imgui::Viewport, _instance: u64, _out_surface: &mut u64) -> i32 { 0 } + fn create_vk_surface( + &mut self, + _viewport: &mut imgui::Viewport, + _instance: u64, + _out_surface: &mut u64, + ) -> i32 { + 0 + } } #[cfg(feature = "viewports")] @@ -548,6 +552,18 @@ struct ViewportState { minimized: bool, } +#[cfg(feature = "viewports")] +pub trait WinitPlatformViewportStorage { + fn create_window(&mut self, id: imgui::Id, flags: imgui::ViewportFlags); + fn remove_windows(&mut self, filter: impl Fn(imgui::Id) -> bool); + fn get_window( + &mut self, + id: winit::window::WindowId, + ) -> Option<(imgui::Id, &winit::window::Window)>; + + fn for_each(&mut self, func: impl FnMut(imgui::Id, &winit::window::Window)); +} + impl WinitPlatform { /// Initializes a winit platform instance and configures imgui. /// @@ -593,17 +609,19 @@ impl WinitPlatform { hidpi_factor: 1.0, cursor_cache: None, mouse_buttons: [Button::INIT; 5], - - #[cfg(feature = "viewports")] - windows: HashMap::new(), } } #[cfg(feature = "viewports")] - pub fn init_viewports(imgui: &mut Context, main_window: &winit::window::Window, event_loop: &winit::event_loop::EventLoop) { + pub fn init_viewports( + imgui: &mut Context, + main_window: &winit::window::Window, + event_loop: &winit::event_loop::EventLoop, + ) { let io = imgui.io_mut(); - io.backend_flags.insert(BackendFlags::PLATFORM_HAS_VIEWPORTS); + io.backend_flags + .insert(BackendFlags::PLATFORM_HAS_VIEWPORTS); imgui.set_platform_backend(ViewportBackend {}); @@ -617,7 +635,10 @@ impl WinitPlatform { dpi_scale: 1.0, }); } - imgui.platform_io_mut().monitors.replace_from_slice(&monitors); + imgui + .platform_io_mut() + .monitors + .replace_from_slice(&monitors); let pos = main_window.inner_position().unwrap(); let pos = [pos.x as f32, pos.y as f32]; @@ -641,42 +662,38 @@ impl WinitPlatform { } #[cfg(feature = "viewports")] - pub fn update_viewports(&mut self, imgui: &mut Context, window_target: &winit::event_loop::EventLoopWindowTarget) { + pub fn update_viewports( + &mut self, + imgui: &mut Context, + storage: &mut impl WinitPlatformViewportStorage, + ) { // remove destroyed windows - self.windows.retain(|id, _| { - imgui.viewports().any(|vp| vp.id == *id) - }); + storage.remove_windows(|id| !imgui.viewports().any(|vp| vp.id == id)); // handle new viewports for viewport in imgui.viewports_mut() { - let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; if state.create { - let window = winit::window::WindowBuilder::new() - .with_always_on_top(state.create_flags.contains(imgui::ViewportFlags::TOP_MOST)) - // .with_decorations(!state.create_flags.contains(imgui::ViewportFlags::NO_DECORATION)) - .with_resizable(true) - .with_visible(false) - .build(window_target) - .unwrap(); - - self.windows.insert(viewport.id, window); - + storage.create_window(viewport.id, viewport.flags); state.create = false; } } // handle other viewport events - for (id, wnd) in &self.windows { - let viewport = imgui.viewport_by_id_mut(*id).unwrap(); - let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + storage.for_each(|id, wnd| { + let viewport = imgui.viewport_by_id_mut(id).unwrap(); + let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; if let Some(pos) = &state.set_pos { let wnd_pos = wnd.outer_position().unwrap(); let inner_pos = wnd.inner_position().unwrap(); let decoration_size = [inner_pos.x - wnd_pos.x, inner_pos.y - wnd_pos.y]; - wnd.set_outer_position(winit::dpi::LogicalPosition::new(pos[0] - decoration_size[0] as f32, pos[1] - decoration_size[1] as f32)); + wnd.set_outer_position(winit::dpi::LogicalPosition::new( + pos[0] - decoration_size[0] as f32, + pos[1] - decoration_size[1] as f32, + )); state.set_pos = None; } if let Some(size) = &state.set_size { @@ -695,7 +712,7 @@ impl WinitPlatform { wnd.set_title(title); state.set_title = None; } - } + }); } /// Attaches the platform instance to a winit window. @@ -1055,33 +1072,33 @@ impl WinitPlatform { } } #[cfg(feature = "viewports")] - pub fn handle_viewport_event(&mut self, imgui: &mut imgui::Context, main_window: &Window, event: &Event) { - if let Event::WindowEvent { window_id, ref event } = *event { - let window = if window_id == main_window.id() { - Some(main_window) + pub fn handle_viewport_event( + &mut self, + imgui: &mut imgui::Context, + main_window: &Window, + storage: &mut impl WinitPlatformViewportStorage, + event: &Event, + ) { + if let Event::WindowEvent { + window_id, + ref event, + } = *event + { + let (viewport, window) = if window_id == main_window.id() { + (imgui.main_viewport_mut(), main_window) } else { - self.windows.iter().find_map(|(_, wnd)| (wnd.id() == window_id).then(|| wnd)) - }; - let window = if let Some(window) = window { - window - } else { - return; - }; - - let viewport = { - if window_id == main_window.id() { - Some(imgui.main_viewport_mut()) + if let Some((viewport_id, window)) = storage.get_window(window_id) { + if let Some(viewport) = imgui.viewport_by_id_mut(viewport_id) { + (viewport, window) + } else { + return; + } } else { - self.windows.iter().find(|(_, wnd)| wnd.id() == window_id).map(|(id, _)| *id).and_then(|id| imgui.viewport_by_id_mut(id)) + return; } }; - let viewport = if let Some(viewport) = viewport { - viewport - } else { - return; - }; - let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; match *event { WindowEvent::Resized(new_size) => { @@ -1091,22 +1108,25 @@ impl WinitPlatform { } else { state.minimized = false; } - }, + } WindowEvent::Moved(_new_pos) => { let pos = window.inner_position().unwrap(); state.pos = [pos.x as f32, pos.y as f32]; - }, + } WindowEvent::CloseRequested => { viewport.platform_request_close = true; - }, + } WindowEvent::Focused(focus) => { state.focus = focus; - }, + } WindowEvent::CursorMoved { position, .. } => { let wnd_pos = window.inner_position().unwrap(); - let pos = [wnd_pos.x as f32 + position.x as f32, wnd_pos.y as f32 + position.y as f32]; + let pos = [ + wnd_pos.x as f32 + position.x as f32, + wnd_pos.y as f32 + position.y as f32, + ]; imgui.io_mut().mouse_pos = pos; - }, + } WindowEvent::KeyboardInput { input: KeyboardInput { @@ -1120,19 +1140,21 @@ impl WinitPlatform { let pressed = state == ElementState::Pressed; io.keys_down[key as usize] = pressed; - + // This is a bit redundant here, but we'll leave it in. The OS occasionally // fails to send modifiers keys, but it doesn't seem to send false-positives, // so double checking isn't terrible in case some system *doesn't* send // device events sometimes. match key { VirtualKeyCode::LShift | VirtualKeyCode::RShift => io.key_shift = pressed, - VirtualKeyCode::LControl | VirtualKeyCode::RControl => io.key_ctrl = pressed, + VirtualKeyCode::LControl | VirtualKeyCode::RControl => { + io.key_ctrl = pressed + } VirtualKeyCode::LAlt | VirtualKeyCode::RAlt => io.key_alt = pressed, VirtualKeyCode::LWin | VirtualKeyCode::RWin => io.key_super = pressed, _ => (), } - }, + } WindowEvent::ReceivedCharacter(ch) if window_id != main_window.id() => { let io = imgui.io_mut(); @@ -1141,7 +1163,7 @@ impl WinitPlatform { if ch != '\u{7f}' { io.add_input_character(ch) } - }, + } WindowEvent::MouseWheel { delta, phase: TouchPhase::Moved, @@ -1178,13 +1200,12 @@ impl WinitPlatform { } _ => (), } - }, - _ => {}, + } + _ => {} } } } - #[cfg(all( not(any( feature = "winit-26", From 3da8f2cf339ed59ed7e30db6b5b44c125dde144b Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Fri, 4 Mar 2022 13:29:01 +0100 Subject: [PATCH 15/42] Polishing for PR --- imgui-examples/Cargo.toml | 2 +- imgui-examples/examples/hello_world.rs | 3 +- imgui-examples/examples/support/mod.rs | 67 ++++++++++++++++++++++++-- imgui-examples/examples/viewports.rs | 5 +- imgui-glium-renderer/src/lib.rs | 3 -- imgui-winit-support/Cargo.toml | 2 +- imgui-winit-support/src/lib.rs | 29 ++++++----- 7 files changed, 85 insertions(+), 26 deletions(-) diff --git a/imgui-examples/Cargo.toml b/imgui-examples/Cargo.toml index 148d06c..2a71724 100644 --- a/imgui-examples/Cargo.toml +++ b/imgui-examples/Cargo.toml @@ -13,6 +13,6 @@ publish = false clipboard = "0.5" glium = { version = "0.31", default-features = true } image = "0.23" -imgui = { path = "../imgui", features = ["tables-api", "docking"] } +imgui = { path = "../imgui", features = ["tables-api"] } imgui-glium-renderer = { path = "../imgui-glium-renderer" } imgui-winit-support = { path = "../imgui-winit-support", features=["viewports"] } diff --git a/imgui-examples/examples/hello_world.rs b/imgui-examples/examples/hello_world.rs index 42d4ce8..1857ecd 100644 --- a/imgui-examples/examples/hello_world.rs +++ b/imgui-examples/examples/hello_world.rs @@ -3,8 +3,7 @@ use imgui::*; mod support; fn main() { - let mut system = support::init(file!()); - system.imgui.io_mut().config_flags.insert(ConfigFlags::VIEWPORTS_ENABLE); + let system = support::init(file!()); let mut value = 0; let choices = ["test test this is 1", "test test this is 2"]; diff --git a/imgui-examples/examples/support/mod.rs b/imgui-examples/examples/support/mod.rs index 1424dcd..5c5a57e 100644 --- a/imgui-examples/examples/support/mod.rs +++ b/imgui-examples/examples/support/mod.rs @@ -3,9 +3,10 @@ use glium::glutin::event::{Event, WindowEvent}; use glium::glutin::event_loop::{ControlFlow, EventLoop}; use glium::glutin::window::WindowBuilder; use glium::{Display, Surface}; -use imgui::{Context, FontConfig, FontGlyphRanges, FontSource, Ui}; +use imgui::{Context, FontConfig, FontGlyphRanges, FontSource, Ui, ViewportFlags}; use imgui_glium_renderer::Renderer; use imgui_winit_support::{HiDpiMode, WinitPlatform}; +use std::collections::HashMap; use std::path::Path; use std::time::Instant; @@ -112,6 +113,46 @@ pub fn init(title: &str) -> System { } } +struct ViewportStorage<'a, T: 'static> { + event_loop: &'a glium::glutin::event_loop::EventLoopWindowTarget, + viewports: &'a mut HashMap, +} + +impl<'a, T> imgui_winit_support::WinitPlatformViewportStorage for ViewportStorage<'a, T> { + fn create_window(&mut self, id: imgui::Id, flags: imgui::ViewportFlags) { + let builder = WindowBuilder::new() + .with_always_on_top(flags.contains(ViewportFlags::TOP_MOST)) + // .with_decorations(!flags.contains(ViewportFlags::NO_DECORATION)) + .with_resizable(true) + .with_visible(false); + + let window = builder.build(self.event_loop).unwrap(); + self.viewports.insert(id, window); + } + + fn remove_windows(&mut self, filter: impl Fn(imgui::Id) -> bool) { + self.viewports.retain(|id, _| !filter(*id)); + } + + fn get_window( + &mut self, + id: glium::glutin::window::WindowId, + ) -> Option<(imgui::Id, &glium::glutin::window::Window)> { + let res = self + .viewports + .iter() + .find(|(_, wnd)| wnd.id() == id) + .map(|(id, wnd)| (*id, wnd)); + res + } + + fn for_each(&mut self, mut func: impl FnMut(imgui::Id, &glium::glutin::window::Window)) { + for (id, wnd) in self.viewports.iter() { + func(*id, wnd); + } + } +} + impl System { pub fn main_loop(self, mut run_ui: F) { let System { @@ -124,6 +165,8 @@ impl System { } = self; let mut last_frame = Instant::now(); + let mut viewports = HashMap::new(); + event_loop.run(move |event, window_target, control_flow| match event { Event::NewEvents(_) => { let now = Instant::now(); @@ -137,7 +180,11 @@ impl System { .expect("Failed to prepare frame"); gl_window.window().request_redraw(); - platform.update_viewports(&mut imgui, window_target); + let mut storage = ViewportStorage { + event_loop: window_target, + viewports: &mut viewports, + }; + platform.update_viewports(&mut imgui, &mut storage); } Event::RedrawRequested(_) => { let ui = imgui.frame(); @@ -164,11 +211,23 @@ impl System { event: WindowEvent::CloseRequested, window_id, .. - } if window_id == display.gl_window().window().id() => *control_flow = ControlFlow::Exit, + } if window_id == display.gl_window().window().id() => { + *control_flow = ControlFlow::Exit + } event => { let gl_window = display.gl_window(); platform.handle_event(imgui.io_mut(), gl_window.window(), &event); - platform.handle_viewport_event(&mut imgui, gl_window.window(), &event); + + let mut storage = ViewportStorage { + event_loop: window_target, + viewports: &mut viewports, + }; + platform.handle_viewport_event( + &mut imgui, + gl_window.window(), + &mut storage, + &event, + ); } }) } diff --git a/imgui-examples/examples/viewports.rs b/imgui-examples/examples/viewports.rs index 3783460..f328e4d 100644 --- a/imgui-examples/examples/viewports.rs +++ b/imgui-examples/examples/viewports.rs @@ -1,4 +1 @@ - -fn main() { - -} +fn main() {} diff --git a/imgui-glium-renderer/src/lib.rs b/imgui-glium-renderer/src/lib.rs index b1ea68b..eddc659 100644 --- a/imgui-glium-renderer/src/lib.rs +++ b/imgui-glium-renderer/src/lib.rs @@ -150,9 +150,6 @@ impl Renderer { ctx.io_mut() .backend_flags .insert(BackendFlags::RENDERER_HAS_VTX_OFFSET); - ctx.io_mut() - .backend_flags - .insert(BackendFlags::RENDERER_HAS_VIEWPORTS); Ok(Renderer { ctx: Rc::clone(facade.get_context()), program, diff --git a/imgui-winit-support/Cargo.toml b/imgui-winit-support/Cargo.toml index f9ca765..cae6bd3 100644 --- a/imgui-winit-support/Cargo.toml +++ b/imgui-winit-support/Cargo.toml @@ -20,7 +20,7 @@ winit-25 = { version = "0.25", package = "winit", default-features = false, opti winit-26 = { version = "0.26", package = "winit", default-features = false, optional = true } [features] -default = ["winit-26/default", "viewports"] +default = ["winit-26/default"] test = ["winit-23/default", "winit-24/default", "winit-25/default", "winit-26/default"] viewports = [ "imgui/docking" ] diff --git a/imgui-winit-support/src/lib.rs b/imgui-winit-support/src/lib.rs index a7a14b6..3e484e5 100644 --- a/imgui-winit-support/src/lib.rs +++ b/imgui-winit-support/src/lib.rs @@ -189,8 +189,8 @@ use winit_20 as winit; use winit_19 as winit; use imgui::{self, BackendFlags, ConfigFlags, Context, Io, Key, Ui}; +use std::cell::Cell; use std::cmp::Ordering; -use std::{cell::Cell, collections::HashMap}; use winit::dpi::{LogicalPosition, LogicalSize}; #[cfg(all( @@ -452,7 +452,6 @@ impl imgui::PlatformViewportBackend for ViewportBackend { fn create_window(&mut self, viewport: &mut imgui::Viewport) { viewport.platform_user_data = Box::into_raw(Box::new(ViewportState { create: true, - create_flags: viewport.flags, set_show: false, set_pos: None, set_size: None, @@ -538,7 +537,6 @@ impl imgui::PlatformViewportBackend for ViewportBackend { #[cfg(feature = "viewports")] struct ViewportState { create: bool, - create_flags: imgui::ViewportFlags, set_show: bool, set_pos: Option<[f32; 2]>, @@ -648,7 +646,6 @@ impl WinitPlatform { let main_viewport = imgui.main_viewport_mut(); main_viewport.platform_user_data = Box::into_raw(Box::new(ViewportState { create: false, - create_flags: imgui::ViewportFlags::empty(), set_show: false, set_pos: None, set_size: None, @@ -1079,6 +1076,18 @@ impl WinitPlatform { storage: &mut impl WinitPlatformViewportStorage, event: &Event, ) { + if !imgui + .io() + .backend_flags + .contains(BackendFlags::PLATFORM_HAS_VIEWPORTS | BackendFlags::RENDERER_HAS_VIEWPORTS) + || !imgui + .io() + .config_flags + .contains(ConfigFlags::VIEWPORTS_ENABLE) + { + return; + } + if let Event::WindowEvent { window_id, ref event, @@ -1086,16 +1095,14 @@ impl WinitPlatform { { let (viewport, window) = if window_id == main_window.id() { (imgui.main_viewport_mut(), main_window) - } else { - if let Some((viewport_id, window)) = storage.get_window(window_id) { - if let Some(viewport) = imgui.viewport_by_id_mut(viewport_id) { - (viewport, window) - } else { - return; - } + } else if let Some((viewport_id, window)) = storage.get_window(window_id) { + if let Some(viewport) = imgui.viewport_by_id_mut(viewport_id) { + (viewport, window) } else { return; } + } else { + return; }; let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; From 768034a681f68d37a5b5797b4e4aa86af989d85e Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Fri, 4 Mar 2022 15:49:43 +0100 Subject: [PATCH 16/42] Added Documentation --- imgui/src/context.rs | 58 ++++++++++++++++++++++++++++++---- imgui/src/io.rs | 2 ++ imgui/src/platform_io.rs | 67 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 120 insertions(+), 7 deletions(-) diff --git a/imgui/src/context.rs b/imgui/src/context.rs index 75d018d..5cb7abb 100644 --- a/imgui/src/context.rs +++ b/imgui/src/context.rs @@ -60,6 +60,8 @@ pub struct Context { // imgui a mutable pointer to it. clipboard_ctx: Box>, + // we need to store an owning reference to our PlatformViewportBackend and PlatformRendererBackend, + // so that it is ensured that PlatformIo::backend_platform_user_data and PlatformIo::backend_renderer_user_data remain valid #[cfg(feature = "docking")] platform_viewport_ctx: Box>, #[cfg(feature = "docking")] @@ -592,39 +594,77 @@ impl Context { #[cfg(feature = "docking")] impl Context { + /// Returns an immutable reference to the Context's [`PlatformIo`](crate::PlatformIo) object. pub fn platform_io(&self) -> &crate::PlatformIo { unsafe { // safe because PlatformIo is a transparent wrapper around sys::ImGuiPlatformIO + // and &self ensures we have shared ownership of PlatformIo. &*(sys::igGetPlatformIO() as *const crate::PlatformIo) } } + /// Returns a mutable reference to the Context's [`PlatformIo`](crate::PlatformIo) object. pub fn platform_io_mut(&mut self) -> &mut crate::PlatformIo { unsafe { // safe because PlatformIo is a transparent wrapper around sys::ImGuiPlatformIO + // and &mut self ensures exclusive ownership of PlatformIo. &mut *(sys::igGetPlatformIO() as *mut crate::PlatformIo) } } + /// Returns an immutable reference to the main [`Viewport`](crate::Viewport) pub fn main_viewport(&self) -> &crate::Viewport { - unsafe { &*(sys::igGetMainViewport() as *mut crate::Viewport) } + unsafe { + // safe because Viewport is a transparent wrapper around sys::ImGuiViewport + // and &self ensures we have shared ownership. + &*(sys::igGetMainViewport() as *mut crate::Viewport) + } } + /// Returns a mutable reference to the main [`Viewport`](crate::Viewport) pub fn main_viewport_mut(&mut self) -> &mut crate::Viewport { - unsafe { &mut *(sys::igGetMainViewport() as *mut crate::Viewport) } + unsafe { + // safe because Viewport is a transparent wrapper around sys::ImGuiViewport + // and &mut self ensures we have exclusive ownership. + &mut *(sys::igGetMainViewport() as *mut crate::Viewport) + } } + /// Tries to find and return a Viewport identified by `id`. + /// + /// # Returns + /// A [`Viewport`](crate::Viewport) with the given `id` + /// or `None` if no [`Viewport`](crate::Viewport) exists. pub fn viewport_by_id(&self, id: crate::Id) -> Option<&crate::Viewport> { - unsafe { (sys::igFindViewportByID(id.0) as *const crate::Viewport).as_ref() } + unsafe { + // safe because Viewport is a transparent wrapper around sys::ImGuiViewport + // and &self ensures shared ownership. + (sys::igFindViewportByID(id.0) as *const crate::Viewport).as_ref() + } } + /// Tries to find and return a Viewport identified by `id`. + /// + /// # Returns + /// A [`Viewport`](crate::Viewport) with the given `id` + /// or `None` if no [`Viewport`](crate::Viewport) exists. pub fn viewport_by_id_mut(&mut self, id: crate::Id) -> Option<&mut crate::Viewport> { - unsafe { (sys::igFindViewportByID(id.0) as *mut crate::Viewport).as_mut() } + unsafe { + // safe because Viewport is a transparent wrapper around sys::ImGuiViewport + // and &mut self ensures exclusive ownership. + (sys::igFindViewportByID(id.0) as *mut crate::Viewport).as_mut() + } } + /// Returns an iterator containing every [`Viewport`](crate::Viewport) that currently exists. pub fn viewports(&self) -> impl Iterator { let slice = self.platform_io().viewports.as_slice(); + // safe because &self ensures shared ownership unsafe { slice.iter().map(|ptr| &**ptr) } } + /// Returns an iterator containing every [`Viewport`](crate::Viewport) that currently exists. pub fn viewports_mut(&mut self) -> impl Iterator { let slice = self.platform_io_mut().viewports.as_slice(); + // safe because &self ensures exclusive ownership unsafe { slice.iter().map(|ptr| &mut **ptr) } } + /// Installs a [`PlatformViewportBackend`](crate::PlatformViewportBackend) that is used to + /// create platform windows on demand if a window is dragged outside of the main viewport. pub fn set_platform_backend(&mut self, backend: T) { let ctx = Box::new(UnsafeCell::new(crate::PlatformViewportContext { backend: Box::new(backend), @@ -638,7 +678,7 @@ impl Context { pio.platform_destroy_window = Some(crate::platform_io::platform_destroy_window); pio.platform_show_window = Some(crate::platform_io::platform_show_window); pio.platform_set_window_pos = Some(crate::platform_io::platform_set_window_pos); - // pio.platform_get_window_pos = Some(crate::platform_io::platform_get_window_pos); + // since pio.platform_get_window_pos is not a C compatible function, cimgui provides an extra function to set it. unsafe { crate::platform_io::ImGuiPlatformIO_Set_Platform_GetWindowPos( pio, @@ -646,7 +686,7 @@ impl Context { ); } pio.platform_set_window_size = Some(crate::platform_io::platform_set_window_size); - // pio.platform_get_window_size = Some(crate::platform_io::platform_get_window_size); + // since pio.platform_get_window_size is not a C compatible function, cimgui provides an extra function to set it. unsafe { crate::platform_io::ImGuiPlatformIO_Set_Platform_GetWindowSize( pio, @@ -665,6 +705,8 @@ impl Context { self.platform_viewport_ctx = ctx; } + /// Installs a [`RendererViewportBackend`](crate::RendererViewportBackend) that is used to + /// render extra viewports created by ImGui. pub fn set_renderer_backend(&mut self, backend: T) { let ctx = Box::new(UnsafeCell::new(crate::RendererViewportContext { backend: Box::new(backend), @@ -682,11 +724,15 @@ impl Context { self.renderer_viewport_ctx = ctx; } + /// Updates the extra Viewports created by ImGui. + /// Has to be called every frame if Viewports are enabled. pub fn update_platform_windows(&mut self) { unsafe { sys::igUpdatePlatformWindows(); } } + /// Basically just calls the [`PlatformViewportBackend`](crate::PlatformViewportBackend) and [`RendererViewportBackend`](crate::RendererViewportBackend) + /// functions. If you render your extra viewports manually this function is not needed at all. pub fn render_platform_windows_default(&mut self) { unsafe { sys::igRenderPlatformWindowsDefault(std::ptr::null_mut(), std::ptr::null_mut()); diff --git a/imgui/src/io.rs b/imgui/src/io.rs index 46f933a..9f5bece 100644 --- a/imgui/src/io.rs +++ b/imgui/src/io.rs @@ -99,8 +99,10 @@ bitflags! { const RENDERER_HAS_VTX_OFFSET = sys::ImGuiBackendFlags_RendererHasVtxOffset; #[cfg(feature = "docking")] + /// Set if the platform backend supports viewports. const PLATFORM_HAS_VIEWPORTS = sys::ImGuiBackendFlags_PlatformHasViewports; #[cfg(feature = "docking")] + /// Set if the renderer backend supports viewports. const RENDERER_HAS_VIEWPORTS = sys::ImGuiBackendFlags_RendererHasViewports; } } diff --git a/imgui/src/platform_io.rs b/imgui/src/platform_io.rs index 889cbf8..d5c0523 100644 --- a/imgui/src/platform_io.rs +++ b/imgui/src/platform_io.rs @@ -8,6 +8,7 @@ use crate::{ Io, ViewportFlags, }; +/// Holds the information needed to enable multiple viewports. #[repr(C)] pub struct PlatformIo { pub(crate) platform_create_window: Option, @@ -38,6 +39,8 @@ pub struct PlatformIo { pub(crate) renderer_render_window: Option, pub(crate) renderer_swap_buffers: Option, + /// Holds information about the available monitors. + /// Should be initialized and updated by the [`PlatformViewportBackend`]. pub monitors: ImVector, pub(crate) viewports: ImVector<*mut Viewport>, @@ -97,20 +100,55 @@ fn test_platform_io_memory_layout() { assert_field_offset!(viewports, Viewports); } +/// Trait holding functions needed when the platform integration supports viewports. +/// +/// Register it via [`Context::set_platform_backend()`](crate::context::Context::set_platform_backend()) pub trait PlatformViewportBackend: 'static { + /// Called by imgui when a new [`Viewport`] is created. + /// + /// # Notes + /// This function should initiate the creation of a platform window. + /// The window should be invisible. fn create_window(&mut self, viewport: &mut Viewport); + /// Called by imgui when a [`Viewport`] is about to be destroyed. + /// + /// # Notes + /// This function should initiate the destruction of the platform window. fn destroy_window(&mut self, viewport: &mut Viewport); + /// Called by imgui to make a [`Viewport`] visible. fn show_window(&mut self, viewport: &mut Viewport); + /// Called by imgui to reposition a [`Viewport`]. + /// + /// # Notes + /// `pos` specifies the position of the windows content area (excluding title bar etc.) fn set_window_pos(&mut self, viewport: &mut Viewport, pos: [f32; 2]); + /// Called by imgui to get the position of a [`Viewport`]. + /// + /// # Notes + /// You should return the position of the window's content area (excluding title bar etc.) fn get_window_pos(&mut self, viewport: &mut Viewport) -> [f32; 2]; + /// Called by imgui to set the size of a [`Viewport`]. + /// + /// # Notes + /// `size` specifies the size of the window's content area (excluding title bar etc.) fn set_window_size(&mut self, viewport: &mut Viewport, size: [f32; 2]); + /// Called by imgui to get the size of a [`Viewport`]. + /// + /// # Notes + /// you should return the size of the window's content area (excluding title bar etc.) fn get_window_size(&mut self, viewport: &mut Viewport) -> [f32; 2]; + /// Called by imgui to make a [`Viewport`] steal the focus. fn set_window_focus(&mut self, viewport: &mut Viewport); + /// Called by imgui to query whether a [`Viewport`] is in focus. fn get_window_focus(&mut self, viewport: &mut Viewport) -> bool; + /// Called by imgui to query whether a [`Viewport`] is minimized. fn get_window_minimized(&mut self, viewport: &mut Viewport) -> bool; + /// Called by imgui to set a [`Viewport`] title. fn set_window_title(&mut self, viewport: &mut Viewport, title: &str); + /// Called by imgui to set the opacity of an entire [`Viewport`]. + /// + /// If your backend does not support opactiy, it is safe to just do nothing in this function. fn set_window_alpha(&mut self, viewport: &mut Viewport, alpha: f32); - fn update_window(&mut self, viewport: &mut Viewport); fn render_window(&mut self, viewport: &mut Viewport); fn swap_buffers(&mut self, viewport: &mut Viewport); @@ -122,15 +160,19 @@ pub trait PlatformViewportBackend: 'static { ) -> i32; } +/// Used to get the current Contexts [`PlatformViewportContext`]. fn get_platform_ctx() -> &'static mut PlatformViewportContext { unsafe { + // should be safe as it is impossible to call any imgui function on a non-active context. &mut *((*(sys::igGetIO() as *const Io)).backend_platform_user_data as *mut PlatformViewportContext) } } +/// Used to get the current Contexts [`RendererViewportContext`]. fn get_renderer_ctx() -> &'static mut RendererViewportContext { unsafe { + // should be safe as it is impossible to call any imgui function on a non-active context. &mut *((*(sys::igGetIO() as *const Io)).backend_platform_user_data as *mut RendererViewportContext) } @@ -226,6 +268,7 @@ pub(crate) extern "C" fn platform_create_vk_surface( }) } +/// The default [`PlatformViewportBackend`], does nothing. pub(crate) struct DummyPlatformViewportBackend {} impl PlatformViewportBackend for DummyPlatformViewportBackend { fn create_window(&mut self, _viewport: &mut Viewport) { @@ -298,6 +341,7 @@ impl PlatformViewportBackend for DummyPlatformViewportBackend { } } +/// Just holds a [`PlatformViewportBackend`]. pub(crate) struct PlatformViewportContext { pub(crate) backend: Box, } @@ -310,9 +354,15 @@ impl PlatformViewportContext { } } +/// Trait that holds optional functions for a rendering backend to support multiple viewports. +/// +/// It is completely fine to not use this Backend at all, as all functions are optional. pub trait RendererViewportBackend: 'static { + /// Called after [`PlatformViewportBackend::create_window()`]. fn create_window(&mut self, viewport: &mut Viewport); + /// Called before [`PlatformViewportBackend::destroy_window()`]. fn destroy_window(&mut self, viewport: &mut Viewport); + /// Called after [`PlatformViewportBackend::set_window_size()`]. fn set_window_size(&mut self, viewport: &mut Viewport, size: [f32; 2]); fn render_window(&mut self, viewport: &mut Viewport); fn swap_buffers(&mut self, viewport: &mut Viewport); @@ -340,6 +390,7 @@ pub(crate) extern "C" fn renderer_swap_buffers(viewport: *mut Viewport, _arg: *m ctx.backend.swap_buffers(unsafe { &mut *viewport }); } +/// The default [`RendererViewportBackend`], does nothing. pub(crate) struct DummyRendererViewportBackend {} impl RendererViewportBackend for DummyRendererViewportBackend { fn create_window(&mut self, _viewport: &mut Viewport) { @@ -363,6 +414,7 @@ impl RendererViewportBackend for DummyRendererViewportBackend { } } +/// Just holds a [`RendererViewportBackend`]. pub(crate) struct RendererViewportContext { pub(crate) backend: Box, } @@ -375,9 +427,12 @@ impl RendererViewportContext { } } +/// Describes an ImGui Viewport. #[repr(C)] pub struct Viewport { + /// The unique ID of this Viewport. pub id: crate::Id, + /// Flags that describe how the Viewport should behave. pub flags: ViewportFlags, pub pos: [f32; 2], pub size: [f32; 2], @@ -397,6 +452,7 @@ pub struct Viewport { } impl Viewport { + /// Returns the draw data of the respective Viewport. pub fn draw_data(&self) -> &crate::DrawData { unsafe { &*self.draw_data } } @@ -443,11 +499,20 @@ fn test_viewport_memory_layout() { assert_field_offset!(platform_request_close, PlatformRequestClose); } +/// Describes a monitor that can be used by ImGui. #[repr(C)] pub struct PlatformMonitor { + /// Position of the monitor on the virtual desktop. pub main_pos: [f32; 2], + /// Size of the monitor on the virtual desktop. pub main_size: [f32; 2], + /// Working position of the monitor, should exclude task bar etc. + /// + /// Set to `main_pos` if not known. pub work_pos: [f32; 2], + /// Working size of the monitor, should exclude task bar etc. + /// + /// Set to `work_size` if not known. pub work_size: [f32; 2], pub dpi_scale: f32, } From 26df654967cb15a40671ba4bcb05d616c366509f Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Tue, 15 Mar 2022 14:08:17 +0100 Subject: [PATCH 17/42] Removed most example changes, working on viewport example --- imgui-examples/Cargo.toml | 3 + imgui-examples/examples/hello_world.rs | 38 ++-- imgui-examples/examples/support/mod.rs | 67 +------ imgui-examples/examples/viewports.rs | 244 ++++++++++++++++++++++++- 4 files changed, 265 insertions(+), 87 deletions(-) diff --git a/imgui-examples/Cargo.toml b/imgui-examples/Cargo.toml index 2a71724..0961a77 100644 --- a/imgui-examples/Cargo.toml +++ b/imgui-examples/Cargo.toml @@ -16,3 +16,6 @@ image = "0.23" imgui = { path = "../imgui", features = ["tables-api"] } imgui-glium-renderer = { path = "../imgui-glium-renderer" } imgui-winit-support = { path = "../imgui-winit-support", features=["viewports"] } + +glow = "0.11.2" +glutin = "0.28.0" diff --git a/imgui-examples/examples/hello_world.rs b/imgui-examples/examples/hello_world.rs index 1857ecd..fccd32e 100644 --- a/imgui-examples/examples/hello_world.rs +++ b/imgui-examples/examples/hello_world.rs @@ -7,29 +7,25 @@ fn main() { let mut value = 0; let choices = ["test test this is 1", "test test this is 2"]; - let mut open = true; system.main_loop(move |_, ui| { - if open { - ui.window("Hello world") - .opened(&mut open) - .size([300.0, 110.0], Condition::FirstUseEver) - .build(|| { - ui.text_wrapped("Hello world!"); - ui.text_wrapped("こんにちは世界!"); - if ui.button(choices[value]) { - value += 1; - value %= 2; - } + ui.window("Hello world") + .size([300.0, 110.0], Condition::FirstUseEver) + .build(|| { + ui.text_wrapped("Hello world!"); + ui.text_wrapped("こんにちは世界!"); + if ui.button(choices[value]) { + value += 1; + value %= 2; + } - ui.button("This...is...imgui-rs!"); - ui.separator(); - let mouse_pos = ui.io().mouse_pos; - ui.text(format!( - "Mouse Position: ({:.1},{:.1})", - mouse_pos[0], mouse_pos[1] - )); - }); - } + ui.button("This...is...imgui-rs!"); + ui.separator(); + let mouse_pos = ui.io().mouse_pos; + ui.text(format!( + "Mouse Position: ({:.1},{:.1})", + mouse_pos[0], mouse_pos[1] + )); + }); }); } diff --git a/imgui-examples/examples/support/mod.rs b/imgui-examples/examples/support/mod.rs index 5c5a57e..809d0e1 100644 --- a/imgui-examples/examples/support/mod.rs +++ b/imgui-examples/examples/support/mod.rs @@ -3,10 +3,9 @@ use glium::glutin::event::{Event, WindowEvent}; use glium::glutin::event_loop::{ControlFlow, EventLoop}; use glium::glutin::window::WindowBuilder; use glium::{Display, Surface}; -use imgui::{Context, FontConfig, FontGlyphRanges, FontSource, Ui, ViewportFlags}; +use imgui::{Context, FontConfig, FontGlyphRanges, FontSource, Ui}; use imgui_glium_renderer::Renderer; use imgui_winit_support::{HiDpiMode, WinitPlatform}; -use std::collections::HashMap; use std::path::Path; use std::time::Instant; @@ -44,7 +43,6 @@ pub fn init(title: &str) -> System { } let mut platform = WinitPlatform::init(&mut imgui); - WinitPlatform::init_viewports(&mut imgui, display.gl_window().window(), &event_loop); { let gl_window = display.gl_window(); let window = gl_window.window(); @@ -113,46 +111,6 @@ pub fn init(title: &str) -> System { } } -struct ViewportStorage<'a, T: 'static> { - event_loop: &'a glium::glutin::event_loop::EventLoopWindowTarget, - viewports: &'a mut HashMap, -} - -impl<'a, T> imgui_winit_support::WinitPlatformViewportStorage for ViewportStorage<'a, T> { - fn create_window(&mut self, id: imgui::Id, flags: imgui::ViewportFlags) { - let builder = WindowBuilder::new() - .with_always_on_top(flags.contains(ViewportFlags::TOP_MOST)) - // .with_decorations(!flags.contains(ViewportFlags::NO_DECORATION)) - .with_resizable(true) - .with_visible(false); - - let window = builder.build(self.event_loop).unwrap(); - self.viewports.insert(id, window); - } - - fn remove_windows(&mut self, filter: impl Fn(imgui::Id) -> bool) { - self.viewports.retain(|id, _| !filter(*id)); - } - - fn get_window( - &mut self, - id: glium::glutin::window::WindowId, - ) -> Option<(imgui::Id, &glium::glutin::window::Window)> { - let res = self - .viewports - .iter() - .find(|(_, wnd)| wnd.id() == id) - .map(|(id, wnd)| (*id, wnd)); - res - } - - fn for_each(&mut self, mut func: impl FnMut(imgui::Id, &glium::glutin::window::Window)) { - for (id, wnd) in self.viewports.iter() { - func(*id, wnd); - } - } -} - impl System { pub fn main_loop(self, mut run_ui: F) { let System { @@ -165,9 +123,7 @@ impl System { } = self; let mut last_frame = Instant::now(); - let mut viewports = HashMap::new(); - - event_loop.run(move |event, window_target, control_flow| match event { + event_loop.run(move |event, _, control_flow| match event { Event::NewEvents(_) => { let now = Instant::now(); imgui.io_mut().update_delta_time(now - last_frame); @@ -179,12 +135,6 @@ impl System { .prepare_frame(imgui.io_mut(), gl_window.window()) .expect("Failed to prepare frame"); gl_window.window().request_redraw(); - - let mut storage = ViewportStorage { - event_loop: window_target, - viewports: &mut viewports, - }; - platform.update_viewports(&mut imgui, &mut storage); } Event::RedrawRequested(_) => { let ui = imgui.frame(); @@ -204,8 +154,6 @@ impl System { .render(&mut target, draw_data) .expect("Rendering failed"); target.finish().expect("Failed to swap buffers"); - - imgui.update_platform_windows(); } Event::WindowEvent { event: WindowEvent::CloseRequested, @@ -217,17 +165,6 @@ impl System { event => { let gl_window = display.gl_window(); platform.handle_event(imgui.io_mut(), gl_window.window(), &event); - - let mut storage = ViewportStorage { - event_loop: window_target, - viewports: &mut viewports, - }; - platform.handle_viewport_event( - &mut imgui, - gl_window.window(), - &mut storage, - &event, - ); } }) } diff --git a/imgui-examples/examples/viewports.rs b/imgui-examples/examples/viewports.rs index f328e4d..c633c09 100644 --- a/imgui-examples/examples/viewports.rs +++ b/imgui-examples/examples/viewports.rs @@ -1 +1,243 @@ -fn main() {} +use std::mem::size_of; + +use glow::HasContext; +use glutin::{PossiblyCurrent, event_loop::ControlFlow, event::WindowEvent}; +use imgui::DrawVert; + + +fn main() { + let event_loop = glutin::event_loop::EventLoop::new(); + + let mut imgui = imgui::Context::create(); + + let mut main_viewport = Viewport::new(&event_loop, &mut imgui); + + let mut winit_platform = imgui_winit_support::WinitPlatform::init(&mut imgui); + // imgui_winit_support::WinitPlatform::init_viewports(&mut imgui, main_viewport.window.window(), &event_loop); + + event_loop.run(move |event, window_target, control_flow| { + winit_platform.handle_event(imgui.io_mut(), main_viewport.window.window(), &event); + + match event { + glutin::event::Event::WindowEvent { window_id, event: WindowEvent::CloseRequested } => { + if window_id == main_viewport.window.window().id() { + *control_flow = ControlFlow::Exit; + } + }, + glutin::event::Event::MainEventsCleared => { + main_viewport.window.window().request_redraw(); + }, + glutin::event::Event::RedrawRequested(window_id) => { + if window_id == main_viewport.window.window().id() { + winit_platform.prepare_frame(imgui.io_mut(), main_viewport.window.window()).unwrap(); + render(&mut imgui, &mut main_viewport); + } + }, + _ => {} + } + }); +} + +fn render(imgui: &mut imgui::Context, viewport: &mut Viewport) { + let ui = imgui.new_frame(); + + let mut open = true; + ui.show_demo_window(&mut open); + + let draw_data = imgui.render(); + + unsafe { + //viewport.window = viewport.window.make_current().unwrap(); + viewport.context.disable(glow::SCISSOR_TEST); + viewport.context.clear(glow::COLOR_BUFFER_BIT); + viewport.context.enable(glow::SCISSOR_TEST); + + viewport.context.bind_vertex_array(Some(viewport.vao)); + viewport.context.use_program(Some(viewport.shader)); + + let left = draw_data.display_pos[0]; + 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, + ]; + + let loc = viewport.context.get_uniform_location(viewport.shader, "u_Matrix").unwrap(); + viewport.context.uniform_matrix_4_f32_slice(Some(&loc), false, &matrix); + + viewport.context.blend_func_separate(glow::SRC_ALPHA, glow::ONE_MINUS_SRC_ALPHA, glow::ONE, glow::ZERO); + viewport.context.enable(glow::BLEND); + + viewport.context.bind_buffer(glow::ARRAY_BUFFER, Some(viewport.vbo)); + viewport.context.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(viewport.ibo)); + + viewport.context.bind_texture(glow::TEXTURE_2D, Some(viewport.font_tex)); + + viewport.context.viewport(0, 0, viewport.window.window().inner_size().width as i32, viewport.window.window().inner_size().height as i32); + } + + for draw_list in draw_data.draw_lists() { + unsafe { + viewport.context.buffer_data_u8_slice(glow::ARRAY_BUFFER, std::slice::from_raw_parts(draw_list.vtx_buffer().as_ptr() as *const u8, draw_list.vtx_buffer().len() * size_of::()), glow::STREAM_DRAW); + viewport.context.buffer_data_u8_slice(glow::ELEMENT_ARRAY_BUFFER, std::slice::from_raw_parts(draw_list.idx_buffer().as_ptr() as *const u8, draw_list.idx_buffer().len() * size_of::()), glow::STREAM_DRAW); + viewport.context.bind_vertex_buffer(0, Some(viewport.vbo), 0, size_of::() as i32); + } + + for cmd in draw_list.commands() { + match cmd { + imgui::DrawCmd::Elements { count, cmd_params } => { + unsafe { + let window_height = viewport.window.window().inner_size().height as i32; + + let x = cmd_params.clip_rect[0] as i32; + let y = cmd_params.clip_rect[1] as i32; + let width = (cmd_params.clip_rect[2] - cmd_params.clip_rect[0]) as i32; + let height = (cmd_params.clip_rect[3] - cmd_params.clip_rect[1]) as i32; + + viewport.context.scissor( + x, + window_height - (y + height), + width, + height + ); + viewport.context.enable(glow::SCISSOR_TEST); + viewport.context.draw_elements_base_vertex(glow::TRIANGLES, count as i32, glow::UNSIGNED_SHORT, (cmd_params.idx_offset * size_of::()) as i32, cmd_params.vtx_offset as i32); + } + }, + _ => {}, + } + } + } + + viewport.window.swap_buffers().unwrap(); +} + +struct Viewport { + window: glutin::ContextWrapper, + context: glow::Context, + vao: glow::VertexArray, + vbo: glow::Buffer, + ibo: glow::Buffer, + shader: glow::Program, + font_tex: glow::Texture, +} + +impl Viewport { + fn new(event_loop: &glutin::event_loop::EventLoopWindowTarget, imgui: &mut imgui::Context) -> Self { + let wb = glutin::window::WindowBuilder::new() + .with_inner_size(glutin::dpi::LogicalSize::new(800.0, 600.0)) + .with_resizable(true) + .with_title("Viewports") + .with_visible(true); + let window = unsafe{glutin::ContextBuilder::new() + .with_double_buffer(Some(true)) + .with_vsync(true) + .build_windowed(wb, &event_loop) + .unwrap() + .make_current() + .unwrap()}; + + let context = unsafe{glow::Context::from_loader_function(|s| window.get_proc_address(s) as *const _)}; + + let (vao, vbo, ibo, shader, font_tex) = unsafe { + let vao = context.create_vertex_array().unwrap(); + let vbo = context.create_buffer().unwrap(); + let ibo = context.create_buffer().unwrap(); + + context.bind_vertex_array(Some(vao)); + context.vertex_attrib_binding(0, 0); + context.vertex_attrib_binding(1, 0); + context.vertex_attrib_binding(2, 0); + context.vertex_attrib_format_f32(0, 2, glow::FLOAT, false, 0); + context.vertex_attrib_format_f32(1, 2, glow::FLOAT, false, 8); + context.vertex_attrib_format_f32(2, 4, glow::UNSIGNED_BYTE, true, 16); + context.enable_vertex_attrib_array(0); + context.enable_vertex_attrib_array(1); + context.enable_vertex_attrib_array(2); + context.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(ibo)); + context.bind_vertex_array(None); + + let vertex_shader = context.create_shader(glow::VERTEX_SHADER).unwrap(); + context.shader_source(vertex_shader, VERTEX_SHADER); + context.compile_shader(vertex_shader); + + let fragment_shader = context.create_shader(glow::FRAGMENT_SHADER).unwrap(); + context.shader_source(fragment_shader, FRAGMENT_SHADER); + context.compile_shader(fragment_shader); + + let program = context.create_program().unwrap(); + context.attach_shader(program, vertex_shader); + context.attach_shader(program, fragment_shader); + context.link_program(program); + + context.delete_shader(vertex_shader); + context.delete_shader(fragment_shader); + + let font_tex = context.create_texture().unwrap(); + let data = imgui.fonts().build_rgba32_texture(); + context.bind_texture(glow::TEXTURE_2D, Some(font_tex)); + context.tex_image_2d(glow::TEXTURE_2D, 0, glow::RGBA as i32, data.width as i32, data.height as i32, 0, glow::RGBA, glow::UNSIGNED_BYTE, Some(data.data)); + context.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MAG_FILTER, glow::LINEAR as i32); + context.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MIN_FILTER, glow::LINEAR as i32); + context.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_S, glow::CLAMP_TO_EDGE as i32); + context.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_T, glow::CLAMP_TO_EDGE as i32); + + (vao, vbo, ibo, program, font_tex) + }; + + Self { + window, + context, + vao, + vbo, + ibo, + shader, + font_tex, + } + } +} + +const VERTEX_SHADER: &'static str = "#version 450 core + +layout(location = 0) in vec2 in_Position; +layout(location = 1) in vec2 in_UV; +layout(location = 2) in vec4 in_Color; + +out vec2 v2f_UV; +out vec4 v2f_Color; + +uniform mat4 u_Matrix; + +void main() { + gl_Position = u_Matrix * vec4(in_Position, 0.0, 1.0); + v2f_UV = in_UV; + v2f_Color = in_Color; +} + +"; + +const FRAGMENT_SHADER: &'static str = "#version 450 core + +in vec2 v2f_UV; +in vec4 v2f_Color; + +layout(location = 0) uniform sampler2D u_FontTexture; + +out vec4 out_Color; + +void main() { + vec4 texColor = texture(u_FontTexture, v2f_UV); + vec4 finalColor = texColor * v2f_Color; + + out_Color = finalColor; +} + +"; From 76bd236a958a11e83d68eb6b17e3b02cf676a18f Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Tue, 15 Mar 2022 15:56:38 +0100 Subject: [PATCH 18/42] Implemented working viewport example --- imgui-examples/examples/viewports.rs | 166 +++++++++++++++++++++------ 1 file changed, 129 insertions(+), 37 deletions(-) diff --git a/imgui-examples/examples/viewports.rs b/imgui-examples/examples/viewports.rs index c633c09..de36700 100644 --- a/imgui-examples/examples/viewports.rs +++ b/imgui-examples/examples/viewports.rs @@ -1,36 +1,66 @@ -use std::mem::size_of; +use std::{mem::size_of, collections::HashMap}; use glow::HasContext; use glutin::{PossiblyCurrent, event_loop::ControlFlow, event::WindowEvent}; -use imgui::DrawVert; - +use imgui::{DrawVert, BackendFlags, ConfigFlags, ViewportFlags, DrawData}; fn main() { let event_loop = glutin::event_loop::EventLoop::new(); let mut imgui = imgui::Context::create(); + imgui.io_mut().backend_flags.insert(BackendFlags::RENDERER_HAS_VIEWPORTS); + imgui.io_mut().config_flags.insert(ConfigFlags::DOCKING_ENABLE); + imgui.io_mut().config_flags.insert(ConfigFlags::VIEWPORTS_ENABLE); - let mut main_viewport = Viewport::new(&event_loop, &mut imgui); + let mut main_viewport = Viewport::new(&event_loop, true, true); + main_viewport.init_font_texture(&mut imgui); let mut winit_platform = imgui_winit_support::WinitPlatform::init(&mut imgui); - // imgui_winit_support::WinitPlatform::init_viewports(&mut imgui, main_viewport.window.window(), &event_loop); + imgui_winit_support::WinitPlatform::init_viewports(&mut imgui, main_viewport.window(), &event_loop); + + let mut viewports = HashMap::new(); event_loop.run(move |event, window_target, control_flow| { - winit_platform.handle_event(imgui.io_mut(), main_viewport.window.window(), &event); + winit_platform.handle_event(imgui.io_mut(), main_viewport.window(), &event); + + let mut storage = ViewportStorage { + window_target, + viewports: &mut viewports, + }; + winit_platform.handle_viewport_event(&mut imgui, main_viewport.window(), &mut storage, &event); match event { glutin::event::Event::WindowEvent { window_id, event: WindowEvent::CloseRequested } => { - if window_id == main_viewport.window.window().id() { + if window_id == main_viewport.window().id() { *control_flow = ControlFlow::Exit; } }, glutin::event::Event::MainEventsCleared => { - main_viewport.window.window().request_redraw(); + main_viewport.window().request_redraw(); }, glutin::event::Event::RedrawRequested(window_id) => { - if window_id == main_viewport.window.window().id() { - winit_platform.prepare_frame(imgui.io_mut(), main_viewport.window.window()).unwrap(); - render(&mut imgui, &mut main_viewport); + if window_id == main_viewport.window().id() { + winit_platform.prepare_frame(imgui.io_mut(), main_viewport.window()).unwrap(); + + render(&mut imgui); + + imgui.update_platform_windows(); + + let mut storage = ViewportStorage { + window_target, + viewports: &mut viewports, + }; + winit_platform.update_viewports(&mut imgui, &mut storage); + + let main_draw_data = imgui.render(); + render_viewport(&mut main_viewport, main_draw_data); + + for (id, viewport) in &mut viewports { + viewport.init_font_texture(&mut imgui); + + let draw_data = imgui.viewport_by_id(*id).unwrap().draw_data(); + render_viewport(viewport, draw_data); + } } }, _ => {} @@ -38,16 +68,21 @@ fn main() { }); } -fn render(imgui: &mut imgui::Context, viewport: &mut Viewport) { +fn render(imgui: &mut imgui::Context) { let ui = imgui.new_frame(); let mut open = true; ui.show_demo_window(&mut open); - let draw_data = imgui.render(); + ui.end_frame_early(); +} + +fn render_viewport(viewport: &mut Viewport, draw_data: &DrawData) { + let pos = viewport.window().inner_position().unwrap(); unsafe { - //viewport.window = viewport.window.make_current().unwrap(); + viewport.make_current(); + viewport.context.disable(glow::SCISSOR_TEST); viewport.context.clear(glow::COLOR_BUFFER_BIT); viewport.context.enable(glow::SCISSOR_TEST); @@ -79,9 +114,9 @@ fn render(imgui: &mut imgui::Context, viewport: &mut Viewport) { viewport.context.bind_buffer(glow::ARRAY_BUFFER, Some(viewport.vbo)); viewport.context.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(viewport.ibo)); - viewport.context.bind_texture(glow::TEXTURE_2D, Some(viewport.font_tex)); + viewport.context.bind_texture(glow::TEXTURE_2D, viewport.font_tex); - viewport.context.viewport(0, 0, viewport.window.window().inner_size().width as i32, viewport.window.window().inner_size().height as i32); + viewport.context.viewport(0, 0, viewport.window().inner_size().width as i32, viewport.window().inner_size().height as i32); } for draw_list in draw_data.draw_lists() { @@ -95,10 +130,10 @@ fn render(imgui: &mut imgui::Context, viewport: &mut Viewport) { match cmd { imgui::DrawCmd::Elements { count, cmd_params } => { unsafe { - let window_height = viewport.window.window().inner_size().height as i32; + let window_height = viewport.window().inner_size().height as i32; - let x = cmd_params.clip_rect[0] as i32; - let y = cmd_params.clip_rect[1] as i32; + let x = cmd_params.clip_rect[0] as i32 - pos.x; + let y = cmd_params.clip_rect[1] as i32 - pos.y; let width = (cmd_params.clip_rect[2] - cmd_params.clip_rect[0]) as i32; let height = (cmd_params.clip_rect[3] - cmd_params.clip_rect[1]) as i32; @@ -117,26 +152,57 @@ fn render(imgui: &mut imgui::Context, viewport: &mut Viewport) { } } - viewport.window.swap_buffers().unwrap(); + viewport.swap_buffers(); +} + +struct ViewportStorage<'a, T: 'static> { + window_target: &'a glutin::event_loop::EventLoopWindowTarget, + viewports: &'a mut HashMap, +} + +impl<'a, T: 'static> imgui_winit_support::WinitPlatformViewportStorage for ViewportStorage<'a, T> { + fn create_window(&mut self, id: imgui::Id, flags: imgui::ViewportFlags) { + let viewport = Viewport::new(self.window_target, false, !flags.contains(ViewportFlags::NO_DECORATION)); + self.viewports.insert(id, viewport); + } + + fn remove_windows(&mut self, filter: impl Fn(imgui::Id) -> bool) { + self.viewports.retain(|id, _| !filter(*id)); + } + + fn get_window( + &mut self, + id: glutin::window::WindowId, + ) -> Option<(imgui::Id, &glutin::window::Window)> { + self.viewports.iter().find(|(viewport_id, viewport)| viewport.window().id() == id) + .map(|(viewport_id, viewport)| (*viewport_id, viewport.window())) + } + + fn for_each(&mut self, mut func: impl FnMut(imgui::Id, &glutin::window::Window)) { + self.viewports.iter().for_each(|(id, vp)| { + func(*id, vp.window()); + }); + } } struct Viewport { - window: glutin::ContextWrapper, + window: Option>, context: glow::Context, vao: glow::VertexArray, vbo: glow::Buffer, ibo: glow::Buffer, shader: glow::Program, - font_tex: glow::Texture, + font_tex: Option, } impl Viewport { - fn new(event_loop: &glutin::event_loop::EventLoopWindowTarget, imgui: &mut imgui::Context) -> Self { + fn new(event_loop: &glutin::event_loop::EventLoopWindowTarget, visible: bool, decorated: bool) -> Self { let wb = glutin::window::WindowBuilder::new() .with_inner_size(glutin::dpi::LogicalSize::new(800.0, 600.0)) .with_resizable(true) .with_title("Viewports") - .with_visible(true); + .with_visible(visible) + .with_decorations(decorated); let window = unsafe{glutin::ContextBuilder::new() .with_double_buffer(Some(true)) .with_vsync(true) @@ -147,7 +213,7 @@ impl Viewport { let context = unsafe{glow::Context::from_loader_function(|s| window.get_proc_address(s) as *const _)}; - let (vao, vbo, ibo, shader, font_tex) = unsafe { + let (vao, vbo, ibo, shader) = unsafe { let vao = context.create_vertex_array().unwrap(); let vbo = context.create_buffer().unwrap(); let ibo = context.create_buffer().unwrap(); @@ -181,28 +247,54 @@ impl Viewport { context.delete_shader(vertex_shader); context.delete_shader(fragment_shader); - let font_tex = context.create_texture().unwrap(); - let data = imgui.fonts().build_rgba32_texture(); - context.bind_texture(glow::TEXTURE_2D, Some(font_tex)); - context.tex_image_2d(glow::TEXTURE_2D, 0, glow::RGBA as i32, data.width as i32, data.height as i32, 0, glow::RGBA, glow::UNSIGNED_BYTE, Some(data.data)); - context.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MAG_FILTER, glow::LINEAR as i32); - context.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MIN_FILTER, glow::LINEAR as i32); - context.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_S, glow::CLAMP_TO_EDGE as i32); - context.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_T, glow::CLAMP_TO_EDGE as i32); - - (vao, vbo, ibo, program, font_tex) + (vao, vbo, ibo, program) }; Self { - window, + window: Some(window), context, vao, vbo, ibo, shader, - font_tex, + font_tex: None, } } + + fn init_font_texture(&mut self, imgui: &mut imgui::Context) { + if self.font_tex.is_some() { + return; + } + + unsafe { + self.make_current(); + + let font_tex = self.context.create_texture().unwrap(); + + let data = imgui.fonts().build_rgba32_texture(); + self.context.bind_texture(glow::TEXTURE_2D, Some(font_tex)); + self.context.tex_image_2d(glow::TEXTURE_2D, 0, glow::RGBA as i32, data.width as i32, data.height as i32, 0, glow::RGBA, glow::UNSIGNED_BYTE, Some(data.data)); + self.context.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MAG_FILTER, glow::LINEAR as i32); + self.context.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MIN_FILTER, glow::LINEAR as i32); + self.context.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_S, glow::CLAMP_TO_EDGE as i32); + self.context.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_T, glow::CLAMP_TO_EDGE as i32); + + self.font_tex = Some(font_tex); + } + } + + fn window(&self) -> &glutin::window::Window { + self.window.as_ref().unwrap().window() + } + + fn make_current(&mut self) { + let window = self.window.take().unwrap(); + self.window = unsafe{Some(window.make_current().unwrap())}; + } + + fn swap_buffers(&self) { + self.window.as_ref().unwrap().swap_buffers().unwrap(); + } } const VERTEX_SHADER: &'static str = "#version 450 core From cbb98f5289242e2fab1ff05e3ced473f49630350 Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Tue, 15 Mar 2022 16:09:03 +0100 Subject: [PATCH 19/42] Added dockspace_over_main_viewport() to Ui, finished basic viewport example --- imgui-examples/examples/viewports.rs | 251 +++++++++++++++++++-------- imgui/src/dock_space.rs | 15 ++ imgui/src/lib.rs | 4 + 3 files changed, 202 insertions(+), 68 deletions(-) create mode 100644 imgui/src/dock_space.rs diff --git a/imgui-examples/examples/viewports.rs b/imgui-examples/examples/viewports.rs index de36700..13d427d 100644 --- a/imgui-examples/examples/viewports.rs +++ b/imgui-examples/examples/viewports.rs @@ -1,22 +1,37 @@ -use std::{mem::size_of, collections::HashMap}; +use std::{collections::HashMap, mem::size_of}; use glow::HasContext; -use glutin::{PossiblyCurrent, event_loop::ControlFlow, event::WindowEvent}; -use imgui::{DrawVert, BackendFlags, ConfigFlags, ViewportFlags, DrawData}; +use glutin::{event::WindowEvent, event_loop::ControlFlow, PossiblyCurrent}; +use imgui::{BackendFlags, ConfigFlags, DrawData, DrawVert, ViewportFlags}; fn main() { let event_loop = glutin::event_loop::EventLoop::new(); let mut imgui = imgui::Context::create(); - imgui.io_mut().backend_flags.insert(BackendFlags::RENDERER_HAS_VIEWPORTS); - imgui.io_mut().config_flags.insert(ConfigFlags::DOCKING_ENABLE); - imgui.io_mut().config_flags.insert(ConfigFlags::VIEWPORTS_ENABLE); + imgui + .io_mut() + .backend_flags + .insert(BackendFlags::RENDERER_HAS_VIEWPORTS); + imgui + .io_mut() + .config_flags + .insert(ConfigFlags::DOCKING_ENABLE); + imgui + .io_mut() + .config_flags + .insert(ConfigFlags::VIEWPORTS_ENABLE); + + imgui.set_ini_filename(None); let mut main_viewport = Viewport::new(&event_loop, true, true); main_viewport.init_font_texture(&mut imgui); let mut winit_platform = imgui_winit_support::WinitPlatform::init(&mut imgui); - imgui_winit_support::WinitPlatform::init_viewports(&mut imgui, main_viewport.window(), &event_loop); + imgui_winit_support::WinitPlatform::init_viewports( + &mut imgui, + main_viewport.window(), + &event_loop, + ); let mut viewports = HashMap::new(); @@ -27,21 +42,31 @@ fn main() { window_target, viewports: &mut viewports, }; - winit_platform.handle_viewport_event(&mut imgui, main_viewport.window(), &mut storage, &event); + winit_platform.handle_viewport_event( + &mut imgui, + main_viewport.window(), + &mut storage, + &event, + ); match event { - glutin::event::Event::WindowEvent { window_id, event: WindowEvent::CloseRequested } => { + glutin::event::Event::WindowEvent { + window_id, + event: WindowEvent::CloseRequested, + } => { if window_id == main_viewport.window().id() { *control_flow = ControlFlow::Exit; } - }, + } glutin::event::Event::MainEventsCleared => { main_viewport.window().request_redraw(); - }, + } glutin::event::Event::RedrawRequested(window_id) => { if window_id == main_viewport.window().id() { - winit_platform.prepare_frame(imgui.io_mut(), main_viewport.window()).unwrap(); - + winit_platform + .prepare_frame(imgui.io_mut(), main_viewport.window()) + .unwrap(); + render(&mut imgui); imgui.update_platform_windows(); @@ -62,7 +87,7 @@ fn main() { render_viewport(viewport, draw_data); } } - }, + } _ => {} } }); @@ -71,6 +96,8 @@ fn main() { fn render(imgui: &mut imgui::Context) { let ui = imgui.new_frame(); + ui.dockspace_over_main_viewport(); + let mut open = true; ui.show_demo_window(&mut open); @@ -95,59 +122,107 @@ fn render_viewport(viewport: &mut Viewport, draw_data: &DrawData) { 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, - + (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 = viewport.context.get_uniform_location(viewport.shader, "u_Matrix").unwrap(); - viewport.context.uniform_matrix_4_f32_slice(Some(&loc), false, &matrix); + let loc = viewport + .context + .get_uniform_location(viewport.shader, "u_Matrix") + .unwrap(); + viewport + .context + .uniform_matrix_4_f32_slice(Some(&loc), false, &matrix); - viewport.context.blend_func_separate(glow::SRC_ALPHA, glow::ONE_MINUS_SRC_ALPHA, glow::ONE, glow::ZERO); + viewport.context.blend_func_separate( + glow::SRC_ALPHA, + glow::ONE_MINUS_SRC_ALPHA, + glow::ONE, + glow::ZERO, + ); viewport.context.enable(glow::BLEND); - viewport.context.bind_buffer(glow::ARRAY_BUFFER, Some(viewport.vbo)); - viewport.context.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(viewport.ibo)); + viewport + .context + .bind_buffer(glow::ARRAY_BUFFER, Some(viewport.vbo)); + viewport + .context + .bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(viewport.ibo)); - viewport.context.bind_texture(glow::TEXTURE_2D, viewport.font_tex); + viewport + .context + .bind_texture(glow::TEXTURE_2D, viewport.font_tex); - viewport.context.viewport(0, 0, viewport.window().inner_size().width as i32, viewport.window().inner_size().height as i32); + viewport.context.viewport( + 0, + 0, + viewport.window().inner_size().width as i32, + viewport.window().inner_size().height as i32, + ); } for draw_list in draw_data.draw_lists() { unsafe { - viewport.context.buffer_data_u8_slice(glow::ARRAY_BUFFER, std::slice::from_raw_parts(draw_list.vtx_buffer().as_ptr() as *const u8, draw_list.vtx_buffer().len() * size_of::()), glow::STREAM_DRAW); - viewport.context.buffer_data_u8_slice(glow::ELEMENT_ARRAY_BUFFER, std::slice::from_raw_parts(draw_list.idx_buffer().as_ptr() as *const u8, draw_list.idx_buffer().len() * size_of::()), glow::STREAM_DRAW); - viewport.context.bind_vertex_buffer(0, Some(viewport.vbo), 0, size_of::() as i32); + viewport.context.buffer_data_u8_slice( + glow::ARRAY_BUFFER, + std::slice::from_raw_parts( + draw_list.vtx_buffer().as_ptr() as *const u8, + draw_list.vtx_buffer().len() * size_of::(), + ), + glow::STREAM_DRAW, + ); + viewport.context.buffer_data_u8_slice( + glow::ELEMENT_ARRAY_BUFFER, + std::slice::from_raw_parts( + draw_list.idx_buffer().as_ptr() as *const u8, + draw_list.idx_buffer().len() * size_of::(), + ), + glow::STREAM_DRAW, + ); + viewport.context.bind_vertex_buffer( + 0, + Some(viewport.vbo), + 0, + size_of::() as i32, + ); } for cmd in draw_list.commands() { - match cmd { - imgui::DrawCmd::Elements { count, cmd_params } => { - unsafe { - let window_height = viewport.window().inner_size().height as i32; + if let imgui::DrawCmd::Elements { count, cmd_params } = cmd { + unsafe { + let window_height = viewport.window().inner_size().height as i32; - let x = cmd_params.clip_rect[0] as i32 - pos.x; - let y = cmd_params.clip_rect[1] as i32 - pos.y; - let width = (cmd_params.clip_rect[2] - cmd_params.clip_rect[0]) as i32; - let height = (cmd_params.clip_rect[3] - cmd_params.clip_rect[1]) as i32; + let x = cmd_params.clip_rect[0] as i32 - pos.x; + let y = cmd_params.clip_rect[1] as i32 - pos.y; + let width = (cmd_params.clip_rect[2] - cmd_params.clip_rect[0]) as i32; + let height = (cmd_params.clip_rect[3] - cmd_params.clip_rect[1]) as i32; - viewport.context.scissor( - x, - window_height - (y + height), - width, - height - ); - viewport.context.enable(glow::SCISSOR_TEST); - viewport.context.draw_elements_base_vertex(glow::TRIANGLES, count as i32, glow::UNSIGNED_SHORT, (cmd_params.idx_offset * size_of::()) as i32, cmd_params.vtx_offset as i32); - } - }, - _ => {}, + viewport + .context + .scissor(x, window_height - (y + height), width, height); + viewport.context.enable(glow::SCISSOR_TEST); + viewport.context.draw_elements_base_vertex( + glow::TRIANGLES, + count as i32, + glow::UNSIGNED_SHORT, + (cmd_params.idx_offset * size_of::()) as i32, + cmd_params.vtx_offset as i32, + ); + } } } } @@ -162,7 +237,11 @@ struct ViewportStorage<'a, T: 'static> { impl<'a, T: 'static> imgui_winit_support::WinitPlatformViewportStorage for ViewportStorage<'a, T> { fn create_window(&mut self, id: imgui::Id, flags: imgui::ViewportFlags) { - let viewport = Viewport::new(self.window_target, false, !flags.contains(ViewportFlags::NO_DECORATION)); + let viewport = Viewport::new( + self.window_target, + false, + !flags.contains(ViewportFlags::NO_DECORATION), + ); self.viewports.insert(id, viewport); } @@ -174,7 +253,9 @@ impl<'a, T: 'static> imgui_winit_support::WinitPlatformViewportStorage for Viewp &mut self, id: glutin::window::WindowId, ) -> Option<(imgui::Id, &glutin::window::Window)> { - self.viewports.iter().find(|(viewport_id, viewport)| viewport.window().id() == id) + self.viewports + .iter() + .find(|(_, viewport)| viewport.window().id() == id) .map(|(viewport_id, viewport)| (*viewport_id, viewport.window())) } @@ -196,22 +277,30 @@ struct Viewport { } impl Viewport { - fn new(event_loop: &glutin::event_loop::EventLoopWindowTarget, visible: bool, decorated: bool) -> Self { + fn new( + event_loop: &glutin::event_loop::EventLoopWindowTarget, + visible: bool, + decorated: bool, + ) -> Self { let wb = glutin::window::WindowBuilder::new() .with_inner_size(glutin::dpi::LogicalSize::new(800.0, 600.0)) .with_resizable(true) .with_title("Viewports") .with_visible(visible) .with_decorations(decorated); - let window = unsafe{glutin::ContextBuilder::new() - .with_double_buffer(Some(true)) - .with_vsync(true) - .build_windowed(wb, &event_loop) - .unwrap() - .make_current() - .unwrap()}; + let window = unsafe { + glutin::ContextBuilder::new() + .with_double_buffer(Some(true)) + .with_vsync(true) + .build_windowed(wb, event_loop) + .unwrap() + .make_current() + .unwrap() + }; - let context = unsafe{glow::Context::from_loader_function(|s| window.get_proc_address(s) as *const _)}; + let context = unsafe { + glow::Context::from_loader_function(|s| window.get_proc_address(s) as *const _) + }; let (vao, vbo, ibo, shader) = unsafe { let vao = context.create_vertex_array().unwrap(); @@ -230,7 +319,7 @@ impl Viewport { context.enable_vertex_attrib_array(2); context.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(ibo)); context.bind_vertex_array(None); - + let vertex_shader = context.create_shader(glow::VERTEX_SHADER).unwrap(); context.shader_source(vertex_shader, VERTEX_SHADER); context.compile_shader(vertex_shader); @@ -243,7 +332,7 @@ impl Viewport { context.attach_shader(program, vertex_shader); context.attach_shader(program, fragment_shader); context.link_program(program); - + context.delete_shader(vertex_shader); context.delete_shader(fragment_shader); @@ -273,11 +362,37 @@ impl Viewport { let data = imgui.fonts().build_rgba32_texture(); self.context.bind_texture(glow::TEXTURE_2D, Some(font_tex)); - self.context.tex_image_2d(glow::TEXTURE_2D, 0, glow::RGBA as i32, data.width as i32, data.height as i32, 0, glow::RGBA, glow::UNSIGNED_BYTE, Some(data.data)); - self.context.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MAG_FILTER, glow::LINEAR as i32); - self.context.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MIN_FILTER, glow::LINEAR as i32); - self.context.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_S, glow::CLAMP_TO_EDGE as i32); - self.context.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_T, glow::CLAMP_TO_EDGE as i32); + self.context.tex_image_2d( + glow::TEXTURE_2D, + 0, + glow::RGBA as i32, + data.width as i32, + data.height as i32, + 0, + glow::RGBA, + glow::UNSIGNED_BYTE, + Some(data.data), + ); + self.context.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_MAG_FILTER, + glow::LINEAR as i32, + ); + self.context.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_MIN_FILTER, + glow::LINEAR as i32, + ); + self.context.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_WRAP_S, + glow::CLAMP_TO_EDGE as i32, + ); + self.context.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_WRAP_T, + glow::CLAMP_TO_EDGE as i32, + ); self.font_tex = Some(font_tex); } @@ -289,7 +404,7 @@ impl Viewport { fn make_current(&mut self) { let window = self.window.take().unwrap(); - self.window = unsafe{Some(window.make_current().unwrap())}; + self.window = unsafe { Some(window.make_current().unwrap()) }; } fn swap_buffers(&self) { @@ -297,7 +412,7 @@ impl Viewport { } } -const VERTEX_SHADER: &'static str = "#version 450 core +const VERTEX_SHADER: &str = "#version 450 core layout(location = 0) in vec2 in_Position; layout(location = 1) in vec2 in_UV; @@ -316,7 +431,7 @@ void main() { "; -const FRAGMENT_SHADER: &'static str = "#version 450 core +const FRAGMENT_SHADER: &str = "#version 450 core in vec2 v2f_UV; in vec4 v2f_Color; diff --git a/imgui/src/dock_space.rs b/imgui/src/dock_space.rs new file mode 100644 index 0000000..ecda162 --- /dev/null +++ b/imgui/src/dock_space.rs @@ -0,0 +1,15 @@ +use std::ptr::null; + +use crate::Ui; + +impl Ui { + pub fn dockspace_over_main_viewport(&self) { + unsafe { + sys::igDockSpaceOverViewport( + sys::igGetMainViewport(), + sys::ImGuiDockNodeFlags_PassthruCentralNode as i32, + null(), + ); + } + } +} diff --git a/imgui/src/lib.rs b/imgui/src/lib.rs index 5edb9a2..14bd06e 100644 --- a/imgui/src/lib.rs +++ b/imgui/src/lib.rs @@ -10,6 +10,8 @@ use std::os::raw::c_char; pub use self::clipboard::*; pub use self::color::ImColor32; pub use self::context::*; +#[cfg(feature = "docking")] +pub use self::dock_space::*; pub use self::drag_drop::{DragDropFlags, DragDropSource, DragDropTarget}; pub use self::draw_list::{ChannelsSplit, DrawListMut}; pub use self::fonts::atlas::*; @@ -63,6 +65,8 @@ mod clipboard; pub mod color; mod columns; mod context; +#[cfg(feature = "docking")] +mod dock_space; pub mod drag_drop; pub mod draw_list; mod fonts; From 57230dc81f62ee8dceb4f979a36d6810b4c8034b Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Wed, 16 Mar 2022 08:53:18 +0100 Subject: [PATCH 20/42] Implemented basic context sharing in viewport example --- imgui-examples/examples/viewports.rs | 165 +++++++++++++++++---------- 1 file changed, 102 insertions(+), 63 deletions(-) diff --git a/imgui-examples/examples/viewports.rs b/imgui-examples/examples/viewports.rs index 13d427d..8f8f515 100644 --- a/imgui-examples/examples/viewports.rs +++ b/imgui-examples/examples/viewports.rs @@ -23,8 +23,8 @@ fn main() { imgui.set_ini_filename(None); - let mut main_viewport = Viewport::new(&event_loop, true, true); - main_viewport.init_font_texture(&mut imgui); + let (mut main_viewport, context) = Viewport::new(&event_loop); + main_viewport.init_font_texture(&mut imgui, &context); let mut winit_platform = imgui_winit_support::WinitPlatform::init(&mut imgui); imgui_winit_support::WinitPlatform::init_viewports( @@ -40,6 +40,8 @@ fn main() { let mut storage = ViewportStorage { window_target, + context: &context, + main_viewport: &main_viewport, viewports: &mut viewports, }; winit_platform.handle_viewport_event( @@ -73,18 +75,20 @@ fn main() { let mut storage = ViewportStorage { window_target, + context: &context, + main_viewport: &main_viewport, viewports: &mut viewports, }; winit_platform.update_viewports(&mut imgui, &mut storage); let main_draw_data = imgui.render(); - render_viewport(&mut main_viewport, main_draw_data); + render_viewport(&mut main_viewport, main_draw_data, &context); for (id, viewport) in &mut viewports { - viewport.init_font_texture(&mut imgui); + viewport.init_font_texture(&mut imgui, &context); let draw_data = imgui.viewport_by_id(*id).unwrap().draw_data(); - render_viewport(viewport, draw_data); + render_viewport(viewport, draw_data, &context); } } } @@ -104,18 +108,18 @@ fn render(imgui: &mut imgui::Context) { ui.end_frame_early(); } -fn render_viewport(viewport: &mut Viewport, draw_data: &DrawData) { +fn render_viewport(viewport: &mut Viewport, draw_data: &DrawData, context: &glow::Context) { let pos = viewport.window().inner_position().unwrap(); unsafe { viewport.make_current(); - viewport.context.disable(glow::SCISSOR_TEST); - viewport.context.clear(glow::COLOR_BUFFER_BIT); - viewport.context.enable(glow::SCISSOR_TEST); + context.disable(glow::SCISSOR_TEST); + context.clear(glow::COLOR_BUFFER_BIT); + context.enable(glow::SCISSOR_TEST); - viewport.context.bind_vertex_array(Some(viewport.vao)); - viewport.context.use_program(Some(viewport.shader)); + context.bind_vertex_array(Some(viewport.vao)); + context.use_program(Some(viewport.shader)); let left = draw_data.display_pos[0]; let right = draw_data.display_pos[0] + draw_data.display_size[0]; @@ -140,34 +144,25 @@ fn render_viewport(viewport: &mut Viewport, draw_data: &DrawData) { 1.0, ]; - let loc = viewport - .context + let loc = context .get_uniform_location(viewport.shader, "u_Matrix") .unwrap(); - viewport - .context - .uniform_matrix_4_f32_slice(Some(&loc), false, &matrix); + context.uniform_matrix_4_f32_slice(Some(&loc), false, &matrix); - viewport.context.blend_func_separate( + context.blend_func_separate( glow::SRC_ALPHA, glow::ONE_MINUS_SRC_ALPHA, glow::ONE, glow::ZERO, ); - viewport.context.enable(glow::BLEND); + context.enable(glow::BLEND); - viewport - .context - .bind_buffer(glow::ARRAY_BUFFER, Some(viewport.vbo)); - viewport - .context - .bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(viewport.ibo)); + context.bind_buffer(glow::ARRAY_BUFFER, Some(viewport.vbo)); + context.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(viewport.ibo)); - viewport - .context - .bind_texture(glow::TEXTURE_2D, viewport.font_tex); + context.bind_texture(glow::TEXTURE_2D, viewport.font_tex); - viewport.context.viewport( + context.viewport( 0, 0, viewport.window().inner_size().width as i32, @@ -177,7 +172,7 @@ fn render_viewport(viewport: &mut Viewport, draw_data: &DrawData) { for draw_list in draw_data.draw_lists() { unsafe { - viewport.context.buffer_data_u8_slice( + context.buffer_data_u8_slice( glow::ARRAY_BUFFER, std::slice::from_raw_parts( draw_list.vtx_buffer().as_ptr() as *const u8, @@ -185,7 +180,7 @@ fn render_viewport(viewport: &mut Viewport, draw_data: &DrawData) { ), glow::STREAM_DRAW, ); - viewport.context.buffer_data_u8_slice( + context.buffer_data_u8_slice( glow::ELEMENT_ARRAY_BUFFER, std::slice::from_raw_parts( draw_list.idx_buffer().as_ptr() as *const u8, @@ -193,12 +188,7 @@ fn render_viewport(viewport: &mut Viewport, draw_data: &DrawData) { ), glow::STREAM_DRAW, ); - viewport.context.bind_vertex_buffer( - 0, - Some(viewport.vbo), - 0, - size_of::() as i32, - ); + context.bind_vertex_buffer(0, Some(viewport.vbo), 0, size_of::() as i32); } for cmd in draw_list.commands() { @@ -211,11 +201,9 @@ fn render_viewport(viewport: &mut Viewport, draw_data: &DrawData) { let width = (cmd_params.clip_rect[2] - cmd_params.clip_rect[0]) as i32; let height = (cmd_params.clip_rect[3] - cmd_params.clip_rect[1]) as i32; - viewport - .context - .scissor(x, window_height - (y + height), width, height); - viewport.context.enable(glow::SCISSOR_TEST); - viewport.context.draw_elements_base_vertex( + context.scissor(x, window_height - (y + height), width, height); + context.enable(glow::SCISSOR_TEST); + context.draw_elements_base_vertex( glow::TRIANGLES, count as i32, glow::UNSIGNED_SHORT, @@ -232,16 +220,15 @@ fn render_viewport(viewport: &mut Viewport, draw_data: &DrawData) { struct ViewportStorage<'a, T: 'static> { window_target: &'a glutin::event_loop::EventLoopWindowTarget, + main_viewport: &'a Viewport, + context: &'a glow::Context, viewports: &'a mut HashMap, } impl<'a, T: 'static> imgui_winit_support::WinitPlatformViewportStorage for ViewportStorage<'a, T> { fn create_window(&mut self, id: imgui::Id, flags: imgui::ViewportFlags) { - let viewport = Viewport::new( - self.window_target, - false, - !flags.contains(ViewportFlags::NO_DECORATION), - ); + let viewport = + Viewport::new_shared(self.window_target, self.main_viewport, self.context, flags); self.viewports.insert(id, viewport); } @@ -268,7 +255,6 @@ impl<'a, T: 'static> imgui_winit_support::WinitPlatformViewportStorage for Viewp struct Viewport { window: Option>, - context: glow::Context, vao: glow::VertexArray, vbo: glow::Buffer, ibo: glow::Buffer, @@ -277,17 +263,13 @@ struct Viewport { } impl Viewport { - fn new( - event_loop: &glutin::event_loop::EventLoopWindowTarget, - visible: bool, - decorated: bool, - ) -> Self { + fn new(event_loop: &glutin::event_loop::EventLoopWindowTarget) -> (Self, glow::Context) { let wb = glutin::window::WindowBuilder::new() .with_inner_size(glutin::dpi::LogicalSize::new(800.0, 600.0)) .with_resizable(true) .with_title("Viewports") - .with_visible(visible) - .with_decorations(decorated); + .with_visible(true) + .with_decorations(true); let window = unsafe { glutin::ContextBuilder::new() .with_double_buffer(Some(true)) @@ -339,9 +321,66 @@ impl Viewport { (vao, vbo, ibo, program) }; + ( + Self { + window: Some(window), + vao, + vbo, + ibo, + shader, + font_tex: None, + }, + context, + ) + } + + fn new_shared( + event_loop: &glutin::event_loop::EventLoopWindowTarget, + main_viewport: &Viewport, + context: &glow::Context, + flags: imgui::ViewportFlags, + ) -> Self { + let wb = glutin::window::WindowBuilder::new() + .with_inner_size(glutin::dpi::LogicalSize::new(100.0, 100.0)) + .with_resizable(true) + .with_title("") + .with_always_on_top(flags.contains(ViewportFlags::TOP_MOST)) + .with_decorations(!flags.contains(ViewportFlags::NO_DECORATION)) + .with_visible(false); + let window = unsafe { + glutin::ContextBuilder::new() + .with_double_buffer(Some(true)) + .with_vsync(true) + .with_shared_lists(main_viewport.window.as_ref().unwrap().context()) + .build_windowed(wb, event_loop) + .unwrap() + .make_current() + .unwrap() + }; + + let (vao, vbo, ibo, shader) = unsafe { + let vao = context.create_vertex_array().unwrap(); + let vbo = context.create_buffer().unwrap(); + let ibo = context.create_buffer().unwrap(); + + context.bind_vertex_array(Some(vao)); + context.vertex_attrib_binding(0, 0); + context.vertex_attrib_binding(1, 0); + context.vertex_attrib_binding(2, 0); + context.vertex_attrib_format_f32(0, 2, glow::FLOAT, false, 0); + context.vertex_attrib_format_f32(1, 2, glow::FLOAT, false, 8); + context.vertex_attrib_format_f32(2, 4, glow::UNSIGNED_BYTE, true, 16); + context.enable_vertex_attrib_array(0); + context.enable_vertex_attrib_array(1); + context.enable_vertex_attrib_array(2); + context.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(ibo)); + context.bind_vertex_array(None); + + (vao, vbo, ibo, main_viewport.shader) + }; + Self { window: Some(window), - context, vao, vbo, ibo, @@ -350,7 +389,7 @@ impl Viewport { } } - fn init_font_texture(&mut self, imgui: &mut imgui::Context) { + fn init_font_texture(&mut self, imgui: &mut imgui::Context, context: &glow::Context) { if self.font_tex.is_some() { return; } @@ -358,11 +397,11 @@ impl Viewport { unsafe { self.make_current(); - let font_tex = self.context.create_texture().unwrap(); + let font_tex = context.create_texture().unwrap(); let data = imgui.fonts().build_rgba32_texture(); - self.context.bind_texture(glow::TEXTURE_2D, Some(font_tex)); - self.context.tex_image_2d( + context.bind_texture(glow::TEXTURE_2D, Some(font_tex)); + context.tex_image_2d( glow::TEXTURE_2D, 0, glow::RGBA as i32, @@ -373,22 +412,22 @@ impl Viewport { glow::UNSIGNED_BYTE, Some(data.data), ); - self.context.tex_parameter_i32( + context.tex_parameter_i32( glow::TEXTURE_2D, glow::TEXTURE_MAG_FILTER, glow::LINEAR as i32, ); - self.context.tex_parameter_i32( + context.tex_parameter_i32( glow::TEXTURE_2D, glow::TEXTURE_MIN_FILTER, glow::LINEAR as i32, ); - self.context.tex_parameter_i32( + context.tex_parameter_i32( glow::TEXTURE_2D, glow::TEXTURE_WRAP_S, glow::CLAMP_TO_EDGE as i32, ); - self.context.tex_parameter_i32( + context.tex_parameter_i32( glow::TEXTURE_2D, glow::TEXTURE_WRAP_T, glow::CLAMP_TO_EDGE as i32, From 14531a074c19403322a23f44558e989e664058c8 Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Fri, 16 Dec 2022 15:00:48 +0100 Subject: [PATCH 21/42] Removed outdated and non-working example --- imgui-examples/examples/viewports.rs | 489 --------------------------- 1 file changed, 489 deletions(-) delete mode 100644 imgui-examples/examples/viewports.rs diff --git a/imgui-examples/examples/viewports.rs b/imgui-examples/examples/viewports.rs deleted file mode 100644 index 8f8f515..0000000 --- a/imgui-examples/examples/viewports.rs +++ /dev/null @@ -1,489 +0,0 @@ -use std::{collections::HashMap, mem::size_of}; - -use glow::HasContext; -use glutin::{event::WindowEvent, event_loop::ControlFlow, PossiblyCurrent}; -use imgui::{BackendFlags, ConfigFlags, DrawData, DrawVert, ViewportFlags}; - -fn main() { - let event_loop = glutin::event_loop::EventLoop::new(); - - let mut imgui = imgui::Context::create(); - imgui - .io_mut() - .backend_flags - .insert(BackendFlags::RENDERER_HAS_VIEWPORTS); - imgui - .io_mut() - .config_flags - .insert(ConfigFlags::DOCKING_ENABLE); - imgui - .io_mut() - .config_flags - .insert(ConfigFlags::VIEWPORTS_ENABLE); - - imgui.set_ini_filename(None); - - let (mut main_viewport, context) = Viewport::new(&event_loop); - main_viewport.init_font_texture(&mut imgui, &context); - - let mut winit_platform = imgui_winit_support::WinitPlatform::init(&mut imgui); - imgui_winit_support::WinitPlatform::init_viewports( - &mut imgui, - main_viewport.window(), - &event_loop, - ); - - let mut viewports = HashMap::new(); - - event_loop.run(move |event, window_target, control_flow| { - winit_platform.handle_event(imgui.io_mut(), main_viewport.window(), &event); - - let mut storage = ViewportStorage { - window_target, - context: &context, - main_viewport: &main_viewport, - viewports: &mut viewports, - }; - winit_platform.handle_viewport_event( - &mut imgui, - main_viewport.window(), - &mut storage, - &event, - ); - - match event { - glutin::event::Event::WindowEvent { - window_id, - event: WindowEvent::CloseRequested, - } => { - if window_id == main_viewport.window().id() { - *control_flow = ControlFlow::Exit; - } - } - glutin::event::Event::MainEventsCleared => { - main_viewport.window().request_redraw(); - } - glutin::event::Event::RedrawRequested(window_id) => { - if window_id == main_viewport.window().id() { - winit_platform - .prepare_frame(imgui.io_mut(), main_viewport.window()) - .unwrap(); - - render(&mut imgui); - - imgui.update_platform_windows(); - - let mut storage = ViewportStorage { - window_target, - context: &context, - main_viewport: &main_viewport, - viewports: &mut viewports, - }; - winit_platform.update_viewports(&mut imgui, &mut storage); - - let main_draw_data = imgui.render(); - render_viewport(&mut main_viewport, main_draw_data, &context); - - for (id, viewport) in &mut viewports { - viewport.init_font_texture(&mut imgui, &context); - - let draw_data = imgui.viewport_by_id(*id).unwrap().draw_data(); - render_viewport(viewport, draw_data, &context); - } - } - } - _ => {} - } - }); -} - -fn render(imgui: &mut imgui::Context) { - let ui = imgui.new_frame(); - - ui.dockspace_over_main_viewport(); - - let mut open = true; - ui.show_demo_window(&mut open); - - ui.end_frame_early(); -} - -fn render_viewport(viewport: &mut Viewport, draw_data: &DrawData, context: &glow::Context) { - let pos = viewport.window().inner_position().unwrap(); - - unsafe { - viewport.make_current(); - - context.disable(glow::SCISSOR_TEST); - context.clear(glow::COLOR_BUFFER_BIT); - context.enable(glow::SCISSOR_TEST); - - context.bind_vertex_array(Some(viewport.vao)); - context.use_program(Some(viewport.shader)); - - let left = draw_data.display_pos[0]; - 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, - ]; - - let loc = context - .get_uniform_location(viewport.shader, "u_Matrix") - .unwrap(); - context.uniform_matrix_4_f32_slice(Some(&loc), false, &matrix); - - context.blend_func_separate( - glow::SRC_ALPHA, - glow::ONE_MINUS_SRC_ALPHA, - glow::ONE, - glow::ZERO, - ); - context.enable(glow::BLEND); - - context.bind_buffer(glow::ARRAY_BUFFER, Some(viewport.vbo)); - context.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(viewport.ibo)); - - context.bind_texture(glow::TEXTURE_2D, viewport.font_tex); - - context.viewport( - 0, - 0, - viewport.window().inner_size().width as i32, - viewport.window().inner_size().height as i32, - ); - } - - for draw_list in draw_data.draw_lists() { - unsafe { - context.buffer_data_u8_slice( - glow::ARRAY_BUFFER, - std::slice::from_raw_parts( - draw_list.vtx_buffer().as_ptr() as *const u8, - draw_list.vtx_buffer().len() * size_of::(), - ), - glow::STREAM_DRAW, - ); - context.buffer_data_u8_slice( - glow::ELEMENT_ARRAY_BUFFER, - std::slice::from_raw_parts( - draw_list.idx_buffer().as_ptr() as *const u8, - draw_list.idx_buffer().len() * size_of::(), - ), - glow::STREAM_DRAW, - ); - context.bind_vertex_buffer(0, Some(viewport.vbo), 0, size_of::() as i32); - } - - for cmd in draw_list.commands() { - if let imgui::DrawCmd::Elements { count, cmd_params } = cmd { - unsafe { - let window_height = viewport.window().inner_size().height as i32; - - let x = cmd_params.clip_rect[0] as i32 - pos.x; - let y = cmd_params.clip_rect[1] as i32 - pos.y; - let width = (cmd_params.clip_rect[2] - cmd_params.clip_rect[0]) as i32; - let height = (cmd_params.clip_rect[3] - cmd_params.clip_rect[1]) as i32; - - context.scissor(x, window_height - (y + height), width, height); - context.enable(glow::SCISSOR_TEST); - context.draw_elements_base_vertex( - glow::TRIANGLES, - count as i32, - glow::UNSIGNED_SHORT, - (cmd_params.idx_offset * size_of::()) as i32, - cmd_params.vtx_offset as i32, - ); - } - } - } - } - - viewport.swap_buffers(); -} - -struct ViewportStorage<'a, T: 'static> { - window_target: &'a glutin::event_loop::EventLoopWindowTarget, - main_viewport: &'a Viewport, - context: &'a glow::Context, - viewports: &'a mut HashMap, -} - -impl<'a, T: 'static> imgui_winit_support::WinitPlatformViewportStorage for ViewportStorage<'a, T> { - fn create_window(&mut self, id: imgui::Id, flags: imgui::ViewportFlags) { - let viewport = - Viewport::new_shared(self.window_target, self.main_viewport, self.context, flags); - self.viewports.insert(id, viewport); - } - - fn remove_windows(&mut self, filter: impl Fn(imgui::Id) -> bool) { - self.viewports.retain(|id, _| !filter(*id)); - } - - fn get_window( - &mut self, - id: glutin::window::WindowId, - ) -> Option<(imgui::Id, &glutin::window::Window)> { - self.viewports - .iter() - .find(|(_, viewport)| viewport.window().id() == id) - .map(|(viewport_id, viewport)| (*viewport_id, viewport.window())) - } - - fn for_each(&mut self, mut func: impl FnMut(imgui::Id, &glutin::window::Window)) { - self.viewports.iter().for_each(|(id, vp)| { - func(*id, vp.window()); - }); - } -} - -struct Viewport { - window: Option>, - vao: glow::VertexArray, - vbo: glow::Buffer, - ibo: glow::Buffer, - shader: glow::Program, - font_tex: Option, -} - -impl Viewport { - fn new(event_loop: &glutin::event_loop::EventLoopWindowTarget) -> (Self, glow::Context) { - let wb = glutin::window::WindowBuilder::new() - .with_inner_size(glutin::dpi::LogicalSize::new(800.0, 600.0)) - .with_resizable(true) - .with_title("Viewports") - .with_visible(true) - .with_decorations(true); - let window = unsafe { - glutin::ContextBuilder::new() - .with_double_buffer(Some(true)) - .with_vsync(true) - .build_windowed(wb, event_loop) - .unwrap() - .make_current() - .unwrap() - }; - - let context = unsafe { - glow::Context::from_loader_function(|s| window.get_proc_address(s) as *const _) - }; - - let (vao, vbo, ibo, shader) = unsafe { - let vao = context.create_vertex_array().unwrap(); - let vbo = context.create_buffer().unwrap(); - let ibo = context.create_buffer().unwrap(); - - context.bind_vertex_array(Some(vao)); - context.vertex_attrib_binding(0, 0); - context.vertex_attrib_binding(1, 0); - context.vertex_attrib_binding(2, 0); - context.vertex_attrib_format_f32(0, 2, glow::FLOAT, false, 0); - context.vertex_attrib_format_f32(1, 2, glow::FLOAT, false, 8); - context.vertex_attrib_format_f32(2, 4, glow::UNSIGNED_BYTE, true, 16); - context.enable_vertex_attrib_array(0); - context.enable_vertex_attrib_array(1); - context.enable_vertex_attrib_array(2); - context.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(ibo)); - context.bind_vertex_array(None); - - let vertex_shader = context.create_shader(glow::VERTEX_SHADER).unwrap(); - context.shader_source(vertex_shader, VERTEX_SHADER); - context.compile_shader(vertex_shader); - - let fragment_shader = context.create_shader(glow::FRAGMENT_SHADER).unwrap(); - context.shader_source(fragment_shader, FRAGMENT_SHADER); - context.compile_shader(fragment_shader); - - let program = context.create_program().unwrap(); - context.attach_shader(program, vertex_shader); - context.attach_shader(program, fragment_shader); - context.link_program(program); - - context.delete_shader(vertex_shader); - context.delete_shader(fragment_shader); - - (vao, vbo, ibo, program) - }; - - ( - Self { - window: Some(window), - vao, - vbo, - ibo, - shader, - font_tex: None, - }, - context, - ) - } - - fn new_shared( - event_loop: &glutin::event_loop::EventLoopWindowTarget, - main_viewport: &Viewport, - context: &glow::Context, - flags: imgui::ViewportFlags, - ) -> Self { - let wb = glutin::window::WindowBuilder::new() - .with_inner_size(glutin::dpi::LogicalSize::new(100.0, 100.0)) - .with_resizable(true) - .with_title("") - .with_always_on_top(flags.contains(ViewportFlags::TOP_MOST)) - .with_decorations(!flags.contains(ViewportFlags::NO_DECORATION)) - .with_visible(false); - let window = unsafe { - glutin::ContextBuilder::new() - .with_double_buffer(Some(true)) - .with_vsync(true) - .with_shared_lists(main_viewport.window.as_ref().unwrap().context()) - .build_windowed(wb, event_loop) - .unwrap() - .make_current() - .unwrap() - }; - - let (vao, vbo, ibo, shader) = unsafe { - let vao = context.create_vertex_array().unwrap(); - let vbo = context.create_buffer().unwrap(); - let ibo = context.create_buffer().unwrap(); - - context.bind_vertex_array(Some(vao)); - context.vertex_attrib_binding(0, 0); - context.vertex_attrib_binding(1, 0); - context.vertex_attrib_binding(2, 0); - context.vertex_attrib_format_f32(0, 2, glow::FLOAT, false, 0); - context.vertex_attrib_format_f32(1, 2, glow::FLOAT, false, 8); - context.vertex_attrib_format_f32(2, 4, glow::UNSIGNED_BYTE, true, 16); - context.enable_vertex_attrib_array(0); - context.enable_vertex_attrib_array(1); - context.enable_vertex_attrib_array(2); - context.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(ibo)); - context.bind_vertex_array(None); - - (vao, vbo, ibo, main_viewport.shader) - }; - - Self { - window: Some(window), - vao, - vbo, - ibo, - shader, - font_tex: None, - } - } - - fn init_font_texture(&mut self, imgui: &mut imgui::Context, context: &glow::Context) { - if self.font_tex.is_some() { - return; - } - - unsafe { - self.make_current(); - - let font_tex = context.create_texture().unwrap(); - - let data = imgui.fonts().build_rgba32_texture(); - context.bind_texture(glow::TEXTURE_2D, Some(font_tex)); - context.tex_image_2d( - glow::TEXTURE_2D, - 0, - glow::RGBA as i32, - data.width as i32, - data.height as i32, - 0, - glow::RGBA, - glow::UNSIGNED_BYTE, - Some(data.data), - ); - context.tex_parameter_i32( - glow::TEXTURE_2D, - glow::TEXTURE_MAG_FILTER, - glow::LINEAR as i32, - ); - context.tex_parameter_i32( - glow::TEXTURE_2D, - glow::TEXTURE_MIN_FILTER, - glow::LINEAR as i32, - ); - context.tex_parameter_i32( - glow::TEXTURE_2D, - glow::TEXTURE_WRAP_S, - glow::CLAMP_TO_EDGE as i32, - ); - context.tex_parameter_i32( - glow::TEXTURE_2D, - glow::TEXTURE_WRAP_T, - glow::CLAMP_TO_EDGE as i32, - ); - - self.font_tex = Some(font_tex); - } - } - - fn window(&self) -> &glutin::window::Window { - self.window.as_ref().unwrap().window() - } - - fn make_current(&mut self) { - let window = self.window.take().unwrap(); - self.window = unsafe { Some(window.make_current().unwrap()) }; - } - - fn swap_buffers(&self) { - self.window.as_ref().unwrap().swap_buffers().unwrap(); - } -} - -const VERTEX_SHADER: &str = "#version 450 core - -layout(location = 0) in vec2 in_Position; -layout(location = 1) in vec2 in_UV; -layout(location = 2) in vec4 in_Color; - -out vec2 v2f_UV; -out vec4 v2f_Color; - -uniform mat4 u_Matrix; - -void main() { - gl_Position = u_Matrix * vec4(in_Position, 0.0, 1.0); - v2f_UV = in_UV; - v2f_Color = in_Color; -} - -"; - -const FRAGMENT_SHADER: &str = "#version 450 core - -in vec2 v2f_UV; -in vec4 v2f_Color; - -layout(location = 0) uniform sampler2D u_FontTexture; - -out vec4 out_Color; - -void main() { - vec4 texColor = texture(u_FontTexture, v2f_UV); - vec4 finalColor = texColor * v2f_Color; - - out_Color = finalColor; -} - -"; From 6bb28843b2f2d294c547712d85a76880679170c4 Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Mon, 19 Dec 2022 16:31:56 +0100 Subject: [PATCH 22/42] Added basic combined renderer --- Cargo.toml | 1 + .../Cargo.toml | 16 + .../examples/basic.rs | 116 +++ .../src/fragment_shader.glsl | 13 + .../src/lib.rs | 767 ++++++++++++++++++ .../src/vertex_shader.glsl | 16 + 6 files changed, 929 insertions(+) create mode 100644 imgui-winit-glow-renderer-viewports/Cargo.toml create mode 100644 imgui-winit-glow-renderer-viewports/examples/basic.rs create mode 100644 imgui-winit-glow-renderer-viewports/src/fragment_shader.glsl create mode 100644 imgui-winit-glow-renderer-viewports/src/lib.rs create mode 100644 imgui-winit-glow-renderer-viewports/src/vertex_shader.glsl diff --git a/Cargo.toml b/Cargo.toml index 2ce437c..c0c9f5c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ "imgui-glow-renderer", "imgui-sdl2-support", "imgui-winit-support", + "imgui-winit-glow-renderer-viewports", "imgui-examples", "xtask", ] diff --git a/imgui-winit-glow-renderer-viewports/Cargo.toml b/imgui-winit-glow-renderer-viewports/Cargo.toml new file mode 100644 index 0000000..9e711dc --- /dev/null +++ b/imgui-winit-glow-renderer-viewports/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "imgui-winit-glow-renderer-viewports" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +imgui = { version="0.9.0", path="../imgui", features=["docking"] } + +glow = "0.11.2" +glutin = "0.30.3" +raw-window-handle = "0.5.0" +winit = "0.27.5" +thiserror = "1.0.38" +glutin-winit = "0.2.1" diff --git a/imgui-winit-glow-renderer-viewports/examples/basic.rs b/imgui-winit-glow-renderer-viewports/examples/basic.rs new file mode 100644 index 0000000..37c9a43 --- /dev/null +++ b/imgui-winit-glow-renderer-viewports/examples/basic.rs @@ -0,0 +1,116 @@ +use std::{ffi::CString, num::NonZeroU32}; + +use glow::{Context, HasContext}; +use glutin::{ + config::ConfigTemplateBuilder, + context::ContextAttributesBuilder, + display::GetGlDisplay, + prelude::{GlDisplay, NotCurrentGlContextSurfaceAccessor, PossiblyCurrentContextGlSurfaceAccessor}, + surface::{SurfaceAttributesBuilder, WindowSurface, GlSurface}, +}; +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}; + +fn main() { + let event_loop = EventLoop::new(); + + let window_builder = WindowBuilder::new() + .with_inner_size(LogicalSize::new(800.0, 600.0)) + .with_visible(true) + .with_resizable(true) + .with_title("Viewports example"); + + let template_builder = ConfigTemplateBuilder::new(); + let (window, gl_config) = DisplayBuilder::new() + .with_window_builder(Some(window_builder)) + .build(&event_loop, template_builder, |mut configs| { + configs.next().unwrap() + }) + .expect("Failed to create main window"); + + let window = window.unwrap(); + + let context_attribs = ContextAttributesBuilder::new().build(Some(window.raw_window_handle())); + let context = unsafe { + gl_config + .display() + .create_context(&gl_config, &context_attribs) + .expect("Failed to create main context") + }; + + let size = window.inner_size(); + let surface_attribs = SurfaceAttributesBuilder::::new().build( + window.raw_window_handle(), + NonZeroU32::new(size.width).unwrap(), + NonZeroU32::new(size.height).unwrap(), + ); + let surface = unsafe { + gl_config + .display() + .create_window_surface(&gl_config, &surface_attribs) + .expect("Failed to create main surface") + }; + + let context = context + .make_current(&surface) + .expect("Failed to make current"); + + let glow = unsafe { + Context::from_loader_function(|name| { + let name = CString::new(name).unwrap(); + context.display().get_proc_address(&name) + }) + }; + + let mut imgui = imgui::Context::create(); + imgui + .io_mut() + .config_flags + .insert(ConfigFlags::DOCKING_ENABLE); + imgui + .io_mut() + .config_flags + .insert(ConfigFlags::VIEWPORTS_ENABLE); + + let mut renderer = Renderer::new(&mut imgui, &window, &glow).expect("Failed to init Renderer"); + + 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::MainEventsCleared => { + window.request_redraw(); + }, + winit::event::Event::RedrawRequested(_) => { + let ui = imgui.frame(); + + ui.show_demo_window(&mut true); + + ui.end_frame_early(); + + imgui.update_platform_windows(); + renderer.update_viewports(&mut imgui, window_target, &glow).expect("Failed to update viewports"); + + let draw_data = imgui.render(); + + context.make_current(&surface).expect("Failed to make current"); + + unsafe { + glow.clear(glow::COLOR_BUFFER_BIT); + } + + renderer.render(&window, &glow, draw_data).expect("Failed to render main viewport"); + + surface.swap_buffers(&context).expect("Failed to swap buffers"); + + renderer.render_viewports(&glow, &mut imgui).expect("Failed to render viewports"); + }, + _ => {}, + } + }); +} diff --git a/imgui-winit-glow-renderer-viewports/src/fragment_shader.glsl b/imgui-winit-glow-renderer-viewports/src/fragment_shader.glsl new file mode 100644 index 0000000..b13bef2 --- /dev/null +++ b/imgui-winit-glow-renderer-viewports/src/fragment_shader.glsl @@ -0,0 +1,13 @@ +#version 450 core + +in vec2 v2f_UV; +in vec4 v2f_Color; + +layout(location = 0) uniform sampler2D u_FontTexture; + +layout(location = 0) out vec4 out_Color; + +void main() { + vec4 tex = texture(u_FontTexture, v2f_UV); + out_Color = v2f_Color * tex; +} diff --git a/imgui-winit-glow-renderer-viewports/src/lib.rs b/imgui-winit-glow-renderer-viewports/src/lib.rs new file mode 100644 index 0000000..59e97e1 --- /dev/null +++ b/imgui-winit-glow-renderer-viewports/src/lib.rs @@ -0,0 +1,767 @@ +use std::{ + cell::RefCell, + collections::{HashMap, VecDeque}, + num::NonZeroU32, + ptr::null_mut, + rc::Rc, slice, +}; + +use glow::HasContext; +use glutin::{ + config::ConfigTemplateBuilder, + context::{ContextAttributesBuilder, NotCurrentContext}, + display::GetGlDisplay, + prelude::{GlDisplay, NotCurrentGlContextSurfaceAccessor, PossiblyCurrentGlContext}, + surface::{Surface, SurfaceAttributesBuilder, WindowSurface, GlSurface}, +}; +use glutin_winit::DisplayBuilder; +use imgui::{BackendFlags, Id, Key, ViewportFlags}; +use raw_window_handle::HasRawWindowHandle; +use thiserror::Error; +use winit::{ + dpi::{PhysicalPosition, PhysicalSize}, + event::{DeviceEvent, ElementState, KeyboardInput, TouchPhase, VirtualKeyCode}, + event_loop::EventLoopWindowTarget, + window::{Window, WindowBuilder}, +}; + +const VERTEX_SHADER: &str = include_str!("vertex_shader.glsl"); +const FRAGMENT_SHADER: &str = include_str!("fragment_shader.glsl"); + +#[derive(Debug, Error)] +pub enum RendererError { + #[error("OpenGL object creation failed: {0}")] + GlObjectCreationError(String), + #[error("Failed to create glutin Display")] + GlutinDisplay, +} + +#[derive(Debug)] +enum ViewportEvent { + Create(Id), + Destroy(Id), + SetPos(Id, [f32; 2]), + SetSize(Id, [f32; 2]), + SetVisible(Id), + SetFocus(Id), + SetTitle(Id, String), +} + +#[derive(Debug)] +pub struct Renderer { + gl_objects: GlObjects, + glutin_config: Option, + extra_windows: HashMap< + Id, + ( + Window, + Option, + Surface, + GlObjects, + ), + >, + event_queue: Rc>>, + font_width: u32, + font_height: u32, + font_pixels: Vec, +} + +#[derive(Debug)] +struct GlObjects { + program: glow::Program, + font_texture: glow::Texture, + vao: glow::VertexArray, + vbo: glow::Buffer, + ibo: glow::Buffer, +} + +impl GlObjects { + pub fn new( + font_width: u32, + font_height: u32, + font_pixels: &[u8], + glow: &glow::Context, + ) -> Result { + let program = unsafe { + let vertex_shader = glow + .create_shader(glow::VERTEX_SHADER) + .map_err(|e| RendererError::GlObjectCreationError(e))?; + glow.shader_source(vertex_shader, VERTEX_SHADER); + glow.compile_shader(vertex_shader); + assert!( + glow.get_shader_compile_status(vertex_shader), + "Vertex Shader contains error" + ); + + let fragment_shader = glow + .create_shader(glow::FRAGMENT_SHADER) + .map_err(|e| RendererError::GlObjectCreationError(e))?; + glow.shader_source(fragment_shader, FRAGMENT_SHADER); + glow.compile_shader(fragment_shader); + assert!( + glow.get_shader_compile_status(fragment_shader), + "Fragment Shader contains error" + ); + + let program = glow + .create_program() + .map_err(|e| RendererError::GlObjectCreationError(e))?; + glow.attach_shader(program, vertex_shader); + glow.attach_shader(program, fragment_shader); + glow.link_program(program); + assert!( + glow.get_program_link_status(program), + "Program contains error" + ); + + glow.delete_shader(vertex_shader); + glow.delete_shader(fragment_shader); + + program + }; + + let font_texture = unsafe { + let tex = glow + .create_texture() + .map_err(|e| RendererError::GlObjectCreationError(e))?; + glow.bind_texture(glow::TEXTURE_2D, Some(tex)); + glow.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_MAG_FILTER, + glow::LINEAR as i32, + ); + glow.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_MIN_FILTER, + glow::LINEAR as i32, + ); + glow.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_WRAP_S, + glow::CLAMP_TO_EDGE as i32, + ); + glow.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_WRAP_T, + glow::CLAMP_TO_EDGE as i32, + ); + glow.tex_image_2d( + glow::TEXTURE_2D, + 0, + glow::RGBA as i32, + font_width as i32, + font_height as i32, + 0, + glow::RGBA, + glow::UNSIGNED_BYTE, + Some(font_pixels), + ); + + 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))? + }; + let ibo = unsafe { + glow.create_buffer() + .map_err(|e| RendererError::GlObjectCreationError(e))? + }; + + Ok(Self { + program, + font_texture, + vao, + vbo, + ibo, + }) + } +} + +impl Renderer { + pub fn new( + imgui: &mut imgui::Context, + main_window: &Window, + gl_context: &glow::Context, + ) -> Result { + let io = imgui.io_mut(); + + io.backend_flags.insert(BackendFlags::HAS_MOUSE_CURSORS); + io.backend_flags.insert(BackendFlags::HAS_SET_MOUSE_POS); + io.backend_flags + .insert(BackendFlags::PLATFORM_HAS_VIEWPORTS); + io.backend_flags + .insert(BackendFlags::RENDERER_HAS_VIEWPORTS); + io.backend_flags + .insert(BackendFlags::RENDERER_HAS_VTX_OFFSET); + + io[Key::Tab] = VirtualKeyCode::Tab as _; + io[Key::LeftArrow] = VirtualKeyCode::Left as _; + io[Key::RightArrow] = VirtualKeyCode::Right as _; + io[Key::UpArrow] = VirtualKeyCode::Up as _; + io[Key::DownArrow] = VirtualKeyCode::Down as _; + io[Key::PageUp] = VirtualKeyCode::PageUp as _; + io[Key::PageDown] = VirtualKeyCode::PageDown as _; + io[Key::Home] = VirtualKeyCode::Home as _; + io[Key::End] = VirtualKeyCode::End as _; + io[Key::Insert] = VirtualKeyCode::Insert as _; + io[Key::Delete] = VirtualKeyCode::Delete as _; + io[Key::Backspace] = VirtualKeyCode::Back as _; + io[Key::Space] = VirtualKeyCode::Space as _; + io[Key::Enter] = VirtualKeyCode::Return as _; + io[Key::Escape] = VirtualKeyCode::Escape as _; + io[Key::KeyPadEnter] = VirtualKeyCode::NumpadEnter as _; + io[Key::A] = VirtualKeyCode::A as _; + io[Key::C] = VirtualKeyCode::C as _; + io[Key::V] = VirtualKeyCode::V as _; + io[Key::X] = VirtualKeyCode::X as _; + io[Key::Y] = VirtualKeyCode::Y as _; + io[Key::Z] = VirtualKeyCode::Z as _; + + let window_size = main_window.inner_size().cast::(); + io.display_size = [window_size.width, window_size.height]; + io.display_framebuffer_scale = [1.0, 1.0]; + + let viewport = imgui.main_viewport_mut(); + + let main_pos = main_window.inner_position().unwrap().cast::(); + + viewport.pos = [main_pos.x, main_pos.y]; + viewport.work_pos = viewport.pos; + viewport.size = [window_size.width, window_size.height]; + viewport.work_size = viewport.size; + viewport.dpi_scale = 1.0; + viewport.platform_user_data = Box::into_raw(Box::new(ViewportData { + pos: [main_pos.x, main_pos.y], + size: [window_size.width, window_size.height], + focus: true, + minimized: false, + })) + .cast(); + + let mut monitors = Vec::new(); + for monitor in main_window.available_monitors() { + monitors.push(imgui::PlatformMonitor { + main_pos: [monitor.position().x as f32, monitor.position().y as f32], + main_size: [monitor.size().width as f32, monitor.size().height as f32], + work_pos: [monitor.position().x as f32, monitor.position().y as f32], + work_size: [monitor.size().width as f32, monitor.size().height as f32], + dpi_scale: 1.0, + }); + } + imgui + .platform_io_mut() + .monitors + .replace_from_slice(&monitors); + + imgui.set_platform_name(Some(format!( + "imgui-winit-glow-renderer-viewports {}", + env!("CARGO_PKG_VERSION") + ))); + imgui.set_renderer_name(Some(format!( + "imgui-winit-glow-renderer-viewports {}", + env!("CARGO_PKG_VERSION") + ))); + + let event_queue = Rc::new(RefCell::new(VecDeque::new())); + + imgui.set_platform_backend(PlatformBackend { + event_queue: event_queue.clone(), + }); + imgui.set_renderer_backend(RendererBackend {}); + + let font_tex = imgui.fonts().build_rgba32_texture(); + let gl_objects = + GlObjects::new(font_tex.width, font_tex.height, font_tex.data, gl_context)?; + + Ok(Self { + gl_objects, + glutin_config: None, + extra_windows: HashMap::new(), + event_queue: Rc::new(RefCell::new(VecDeque::new())), + font_width: font_tex.width, + font_height: font_tex.height, + font_pixels: font_tex.data.to_vec(), + }) + } + + pub fn handle_event( + &mut self, + imgui: &mut imgui::Context, + main_window: &Window, + event: &winit::event::Event, + ) { + match *event { + winit::event::Event::WindowEvent { + window_id, + ref event, + } => { + let viewport = if window_id == main_window.id() { + 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(viewport) = imgui.viewport_by_id_mut(id) { + viewport + } else { + return; + } + } else { + return; + } + }; + + 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; + + 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::CloseRequested if window_id != main_window.id() => { + viewport.platform_request_close = true; + } + winit::event::WindowEvent::ReceivedCharacter(c) => { + imgui.io_mut().add_input_character(c); + } + winit::event::WindowEvent::Focused(f) => unsafe { + (*(viewport.platform_user_data.cast::())).focus = f; + }, + winit::event::WindowEvent::KeyboardInput { + input: + KeyboardInput { + virtual_keycode: Some(key), + state: ElementState::Pressed, + .. + }, + .. + } => { + 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]; + } + winit::event::WindowEvent::MouseWheel { + delta, + phase: TouchPhase::Moved, + .. + } => match delta { + winit::event::MouseScrollDelta::LineDelta(h, v) => { + imgui.io_mut().mouse_wheel_h = h; + imgui.io_mut().mouse_wheel = v; + } + winit::event::MouseScrollDelta::PixelDelta(pos) => { + imgui.io_mut().mouse_wheel_h += if pos.x > 0.0 { + 1.0 + } else if pos.x < 0.0 { + -1.0 + } else { + 0.0 + }; + imgui.io_mut().mouse_wheel += if pos.y > 0.0 { + 1.0 + } else if pos.y < 0.0 { + -1.0 + } else { + 0.0 + }; + } + }, + winit::event::WindowEvent::MouseInput { state, button, .. } => { + let state = state == ElementState::Pressed; + + match button { + winit::event::MouseButton::Left => { + imgui.io_mut().mouse_down[0] = state; + } + winit::event::MouseButton::Right => { + imgui.io_mut().mouse_down[1] = state; + } + winit::event::MouseButton::Middle => { + imgui.io_mut().mouse_down[2] = state; + } + winit::event::MouseButton::Other(index @ 0..=4) => { + imgui.io_mut().mouse_down[index as usize] = state; + } + _ => {} + } + } + _ => {} + } + } + winit::event::Event::DeviceEvent { + event: + DeviceEvent::Key(KeyboardInput { + virtual_keycode: Some(key), + state: ElementState::Released, + .. + }), + .. + } => { + imgui.io_mut().keys_down[key as usize] = false; + } + _ => {} + } + } + + pub fn update_viewports( + &mut self, + imgui: &mut imgui::Context, + window_target: &EventLoopWindowTarget, + glow: &glow::Context, + ) -> Result<(), RendererError> { + loop { + let event = self.event_queue.borrow_mut().pop_front(); + let event = if let Some(event) = event { + event + } else { + break; + }; + + match event { + ViewportEvent::Create(id) => { + if let Some(viewport) = imgui.viewport_by_id_mut(id) { + let extra_window = + self.create_extra_window(viewport, window_target, glow)?; + self.extra_windows.insert(id, extra_window); + } + } + ViewportEvent::Destroy(id) => { + self.extra_windows.remove(&id); + } + ViewportEvent::SetPos(id, pos) => { + if let Some((wnd, _, _, _)) = self.extra_windows.get(&id) { + wnd.set_outer_position(PhysicalPosition::new(pos[0], pos[1])); + } + } + ViewportEvent::SetSize(id, size) => { + if let Some((wnd, _, _, _)) = self.extra_windows.get(&id) { + wnd.set_inner_size(PhysicalSize::new(size[0], size[1])); + } + } + ViewportEvent::SetVisible(id) => { + if let Some((wnd, _, _, _)) = self.extra_windows.get(&id) { + wnd.set_visible(true); + } + } + ViewportEvent::SetFocus(id) => { + if let Some((wnd, _, _, _)) = self.extra_windows.get(&id) { + wnd.focus_window(); + } + } + ViewportEvent::SetTitle(id, title) => { + if let Some((wnd, _, _, _)) = self.extra_windows.get(&id) { + wnd.set_title(&title); + } + } + } + } + + Ok(()) + } + + fn create_extra_window( + &mut self, + viewport: &mut imgui::Viewport, + window_target: &EventLoopWindowTarget, + glow: &glow::Context, + ) -> Result< + ( + Window, + Option, + Surface, + GlObjects, + ), + RendererError, + > { + let window_builder = WindowBuilder::new() + .with_position(PhysicalPosition::new(viewport.pos[0], viewport.pos[1])) + .with_inner_size(PhysicalSize::new(viewport.size[0], viewport.size[1])) + .with_visible(false) + .with_resizable(true) + .with_decorations(!viewport.flags.contains(ViewportFlags::NO_DECORATION)); + + let window = if let Some(glutin_config) = &self.glutin_config { + glutin_winit::finalize_window(window_target, window_builder, glutin_config) + .map_err(|_| RendererError::GlutinDisplay)? + } else { + let template_builder = ConfigTemplateBuilder::new(); + + let (window, cfg) = DisplayBuilder::new() + .with_window_builder(Some(window_builder)) + .build(window_target, template_builder, |mut configs| { + configs.next().unwrap() + }) + .map_err(|_| RendererError::GlutinDisplay)?; + + self.glutin_config = Some(cfg); + + window.unwrap() + }; + + let glutin_config = self.glutin_config.as_ref().unwrap(); + + let context_attribs = + ContextAttributesBuilder::new().build(Some(window.raw_window_handle())); + let context = unsafe { + glutin_config + .display() + .create_context(&glutin_config, &context_attribs) + .map_err(|_| RendererError::GlutinDisplay)? + }; + + let surface_attribs = SurfaceAttributesBuilder::::new().build( + window.raw_window_handle(), + NonZeroU32::new(viewport.size[0] as u32).unwrap(), + NonZeroU32::new(viewport.size[1] as u32).unwrap(), + ); + let surface = unsafe { + glutin_config + .display() + .create_window_surface(glutin_config, &surface_attribs) + .map_err(|_| RendererError::GlutinDisplay)? + }; + + let context = context + .make_current(&surface) + .map_err(|_| RendererError::GlutinDisplay)?; + + let gl_objects = + GlObjects::new(self.font_width, self.font_height, &self.font_pixels, glow)?; + + Ok(( + window, + Some(context.make_not_current().unwrap()), + surface, + gl_objects, + )) + } + + pub fn render( + &mut self, + main_window: &Window, + glow: &glow::Context, + draw_data: &imgui::DrawData, + ) -> Result<(), RendererError> { + Self::render_window(main_window, glow, draw_data, &self.gl_objects) + } + + pub fn render_viewports( + &mut self, + glow: &glow::Context, + imgui: &mut imgui::Context, + ) -> 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)?; + + unsafe { + 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)?; + + *context = Some(current_context.make_not_current().unwrap()); + } + } + + Ok(()) + } + + fn render_window( + window: &Window, + glow: &glow::Context, + draw_data: &imgui::DrawData, + gl_objects: &GlObjects, + ) -> Result<(), RendererError> { + unsafe { + let window_size = window.inner_size(); + + glow.viewport(0, 0, window_size.width as i32, window_size.height as i32); + + 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)); + glow.active_texture(glow::TEXTURE0); + glow.bind_texture(glow::TEXTURE_2D, Some(gl_objects.font_texture)); + glow.use_program(Some(gl_objects.program)); + + let left = draw_data.display_pos[0]; + 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, + ]; + + 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); + + 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); + }, + _ => {}, + } + } + } + } + + Ok(()) + } +} + +struct ViewportData { + pos: [f32; 2], + size: [f32; 2], + focus: bool, + minimized: bool, +} + +struct PlatformBackend { + event_queue: Rc>>, +} + +impl imgui::PlatformViewportBackend for PlatformBackend { + fn create_window(&mut self, viewport: &mut imgui::Viewport) { + viewport.platform_user_data = Box::into_raw(Box::new(ViewportData { + pos: viewport.pos, + size: viewport.size, + focus: false, + minimized: false, + })) + .cast(); + self.event_queue + .borrow_mut() + .push_back(ViewportEvent::Create(viewport.id)); + } + + fn destroy_window(&mut self, viewport: &mut imgui::Viewport) { + unsafe { + drop(Box::from_raw( + viewport.platform_user_data.cast::(), + )); + } + viewport.platform_user_data = null_mut(); + + self.event_queue + .borrow_mut() + .push_back(ViewportEvent::Destroy(viewport.id)); + } + + fn show_window(&mut self, viewport: &mut imgui::Viewport) { + self.event_queue + .borrow_mut() + .push_back(ViewportEvent::SetVisible(viewport.id)); + } + + fn set_window_pos(&mut self, viewport: &mut imgui::Viewport, pos: [f32; 2]) { + self.event_queue + .borrow_mut() + .push_back(ViewportEvent::SetPos(viewport.id, pos)); + } + + fn get_window_pos(&mut self, viewport: &mut imgui::Viewport) -> [f32; 2] { + unsafe { (*(viewport.platform_user_data.cast::())).pos } + } + + fn set_window_size(&mut self, viewport: &mut imgui::Viewport, size: [f32; 2]) { + self.event_queue + .borrow_mut() + .push_back(ViewportEvent::SetSize(viewport.id, size)); + } + + fn get_window_size(&mut self, viewport: &mut imgui::Viewport) -> [f32; 2] { + unsafe { (*(viewport.platform_user_data.cast::())).size } + } + + fn set_window_focus(&mut self, viewport: &mut imgui::Viewport) { + self.event_queue + .borrow_mut() + .push_back(ViewportEvent::SetFocus(viewport.id)); + } + + fn get_window_focus(&mut self, viewport: &mut imgui::Viewport) -> bool { + unsafe { (*(viewport.platform_user_data.cast::())).focus } + } + + fn get_window_minimized(&mut self, viewport: &mut imgui::Viewport) -> bool { + unsafe { (*(viewport.platform_user_data.cast::())).minimized } + } + + fn set_window_title(&mut self, viewport: &mut imgui::Viewport, title: &str) { + self.event_queue + .borrow_mut() + .push_back(ViewportEvent::SetTitle(viewport.id, title.to_owned())); + } + + fn set_window_alpha(&mut self, _viewport: &mut imgui::Viewport, _alpha: f32) {} + + fn update_window(&mut self, _viewport: &mut imgui::Viewport) {} + + fn render_window(&mut self, _viewport: &mut imgui::Viewport) {} + + fn swap_buffers(&mut self, _viewport: &mut imgui::Viewport) {} + + fn create_vk_surface( + &mut self, + _viewport: &mut imgui::Viewport, + _instance: u64, + _out_surface: &mut u64, + ) -> i32 { + 0 + } +} + +struct RendererBackend {} + +impl imgui::RendererViewportBackend for RendererBackend { + fn create_window(&mut self, _viewport: &mut imgui::Viewport) {} + + fn destroy_window(&mut self, _viewport: &mut imgui::Viewport) {} + + fn set_window_size(&mut self, _viewport: &mut imgui::Viewport, _size: [f32; 2]) {} + + fn render_window(&mut self, _viewport: &mut imgui::Viewport) {} + + fn swap_buffers(&mut self, _viewport: &mut imgui::Viewport) {} +} diff --git a/imgui-winit-glow-renderer-viewports/src/vertex_shader.glsl b/imgui-winit-glow-renderer-viewports/src/vertex_shader.glsl new file mode 100644 index 0000000..4d74b81 --- /dev/null +++ b/imgui-winit-glow-renderer-viewports/src/vertex_shader.glsl @@ -0,0 +1,16 @@ +#version 450 + +layout(location = 0) in vec2 in_Position; +layout(location = 1) in vec2 in_UV; +layout(location = 2) in vec4 in_Color; + +uniform mat4 u_Matrix; + +out vec2 v2f_UV; +out vec4 v2f_Color; + +void main() { + gl_Position = u_Matrix * vec4(in_Position, 0.0, 1.0); + v2f_UV = in_UV; + v2f_Color = in_Color; +} From e3bdcffee019ad484fbea405f5aa4a0007dce96a Mon Sep 17 00:00:00 2001 From: Robin Date: Tue, 20 Dec 2022 13:30:45 +0100 Subject: [PATCH 23/42] Fixed bug in platform_io --- imgui/src/platform_io.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui/src/platform_io.rs b/imgui/src/platform_io.rs index d5c0523..3c9b122 100644 --- a/imgui/src/platform_io.rs +++ b/imgui/src/platform_io.rs @@ -173,7 +173,7 @@ fn get_platform_ctx() -> &'static mut PlatformViewportContext { fn get_renderer_ctx() -> &'static mut RendererViewportContext { unsafe { // should be safe as it is impossible to call any imgui function on a non-active context. - &mut *((*(sys::igGetIO() as *const Io)).backend_platform_user_data + &mut *((*(sys::igGetIO() as *const Io)).backend_renderer_user_data as *mut RendererViewportContext) } } From 1d88eceb16e6d680ef28f00ea190f2bd768530ef Mon Sep 17 00:00:00 2001 From: Robin Date: Tue, 20 Dec 2022 13:32:15 +0100 Subject: [PATCH 24/42] Removed viewports code from imgui-winit-support --- imgui-examples/Cargo.toml | 2 +- imgui-examples/examples/support/mod.rs | 5 +- imgui-winit-support/Cargo.toml | 3 - imgui-winit-support/src/lib.rs | 367 ------------------------- 4 files changed, 2 insertions(+), 375 deletions(-) diff --git a/imgui-examples/Cargo.toml b/imgui-examples/Cargo.toml index f158f8d..9b83f0f 100644 --- a/imgui-examples/Cargo.toml +++ b/imgui-examples/Cargo.toml @@ -14,7 +14,7 @@ glium = { version = "0.32.1", default-features = true } image = "0.23" imgui = { path = "../imgui", features = ["tables-api"] } imgui-glium-renderer = { path = "../imgui-glium-renderer" } -imgui-winit-support = { path = "../imgui-winit-support", features=["viewports"] } +imgui-winit-support = { path = "../imgui-winit-support" } # Pin indirect dependency scoped-tls to 1.0.0 # as 1.0.1 bumped MSRV to 1.59 diff --git a/imgui-examples/examples/support/mod.rs b/imgui-examples/examples/support/mod.rs index 809d0e1..44e8825 100644 --- a/imgui-examples/examples/support/mod.rs +++ b/imgui-examples/examples/support/mod.rs @@ -157,11 +157,8 @@ impl System { } Event::WindowEvent { event: WindowEvent::CloseRequested, - window_id, .. - } if window_id == display.gl_window().window().id() => { - *control_flow = ControlFlow::Exit - } + } => *control_flow = ControlFlow::Exit, event => { let gl_window = display.gl_window(); platform.handle_event(imgui.io_mut(), gl_window.window(), &event); diff --git a/imgui-winit-support/Cargo.toml b/imgui-winit-support/Cargo.toml index 7e62be1..641565e 100644 --- a/imgui-winit-support/Cargo.toml +++ b/imgui-winit-support/Cargo.toml @@ -12,6 +12,3 @@ categories = ["gui"] [dependencies] imgui = { version = "0.9.0", path = "../imgui" } winit = { version = "0.27.2", default-features = false } - -[features] -viewports = [ "imgui/docking" ] diff --git a/imgui-winit-support/src/lib.rs b/imgui-winit-support/src/lib.rs index e63cb56..a907fb9 100644 --- a/imgui-winit-support/src/lib.rs +++ b/imgui-winit-support/src/lib.rs @@ -203,124 +203,6 @@ impl HiDpiMode { } } -#[cfg(feature = "viewports")] -struct ViewportBackend {} - -#[cfg(feature = "viewports")] -impl imgui::PlatformViewportBackend for ViewportBackend { - fn create_window(&mut self, viewport: &mut imgui::Viewport) { - viewport.platform_user_data = Box::into_raw(Box::new(ViewportState { - create: true, - set_show: false, - set_pos: None, - set_size: None, - set_focus: false, - set_title: None, - pos: [0.0, 0.0], - size: [0.0, 0.0], - focus: false, - minimized: false, - })) as *mut _; - } - - fn destroy_window(&mut self, viewport: &mut imgui::Viewport) { - unsafe { - Box::from_raw(viewport.platform_user_data as *mut ViewportState); - } - viewport.platform_user_data = std::ptr::null_mut(); - } - - fn show_window(&mut self, viewport: &mut imgui::Viewport) { - let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; - state.set_show = true; - } - - fn set_window_pos(&mut self, viewport: &mut imgui::Viewport, pos: [f32; 2]) { - let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; - state.set_pos = Some(pos); - } - - fn get_window_pos(&mut self, viewport: &mut imgui::Viewport) -> [f32; 2] { - let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; - state.pos - } - - fn set_window_size(&mut self, viewport: &mut imgui::Viewport, size: [f32; 2]) { - let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; - state.set_size = Some(size); - } - - fn get_window_size(&mut self, viewport: &mut imgui::Viewport) -> [f32; 2] { - let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; - state.size - } - - fn set_window_focus(&mut self, viewport: &mut imgui::Viewport) { - let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; - state.set_focus = true; - } - - fn get_window_focus(&mut self, viewport: &mut imgui::Viewport) -> bool { - let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; - state.focus - } - - fn get_window_minimized(&mut self, viewport: &mut imgui::Viewport) -> bool { - let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; - state.minimized - } - - fn set_window_title(&mut self, viewport: &mut imgui::Viewport, title: &str) { - let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; - state.set_title = Some(title.to_string()); - } - - fn set_window_alpha(&mut self, _viewport: &mut imgui::Viewport, _alpha: f32) {} - - fn update_window(&mut self, _viewport: &mut imgui::Viewport) {} - - fn render_window(&mut self, _viewport: &mut imgui::Viewport) {} - - fn swap_buffers(&mut self, _viewport: &mut imgui::Viewport) {} - - fn create_vk_surface( - &mut self, - _viewport: &mut imgui::Viewport, - _instance: u64, - _out_surface: &mut u64, - ) -> i32 { - 0 - } -} - -#[cfg(feature = "viewports")] -struct ViewportState { - create: bool, - - set_show: bool, - set_pos: Option<[f32; 2]>, - set_size: Option<[f32; 2]>, - set_focus: bool, - set_title: Option, - - pos: [f32; 2], - size: [f32; 2], - focus: bool, - minimized: bool, -} - -#[cfg(feature = "viewports")] -pub trait WinitPlatformViewportStorage { - fn create_window(&mut self, id: imgui::Id, flags: imgui::ViewportFlags); - fn remove_windows(&mut self, filter: impl Fn(imgui::Id) -> bool); - fn get_window( - &mut self, - id: winit::window::WindowId, - ) -> Option<(imgui::Id, &winit::window::Window)>; - - fn for_each(&mut self, func: impl FnMut(imgui::Id, &winit::window::Window)); -} - impl WinitPlatform { /// Initializes a winit platform instance and configures imgui. /// @@ -366,109 +248,6 @@ impl WinitPlatform { mouse_buttons: [Button::INIT; 5], } } - - #[cfg(feature = "viewports")] - pub fn init_viewports( - imgui: &mut Context, - main_window: &winit::window::Window, - event_loop: &winit::event_loop::EventLoop, - ) { - let io = imgui.io_mut(); - - io.backend_flags - .insert(BackendFlags::PLATFORM_HAS_VIEWPORTS); - - imgui.set_platform_backend(ViewportBackend {}); - - let mut monitors = Vec::new(); - for monitor in event_loop.available_monitors() { - monitors.push(imgui::PlatformMonitor { - main_pos: [monitor.position().x as f32, monitor.position().y as f32], - main_size: [monitor.size().width as f32, monitor.size().height as f32], - work_pos: [monitor.position().x as f32, monitor.position().y as f32], - work_size: [monitor.size().width as f32, monitor.size().height as f32], - dpi_scale: 1.0, - }); - } - imgui - .platform_io_mut() - .monitors - .replace_from_slice(&monitors); - - let pos = main_window.inner_position().unwrap(); - let pos = [pos.x as f32, pos.y as f32]; - let size = main_window.inner_size(); - let size = [size.width as f32, size.height as f32]; - - let main_viewport = imgui.main_viewport_mut(); - main_viewport.platform_user_data = Box::into_raw(Box::new(ViewportState { - create: false, - set_show: false, - set_pos: None, - set_size: None, - set_focus: false, - set_title: None, - pos, - size, - focus: true, - minimized: false, - })) as *mut _; - } - - #[cfg(feature = "viewports")] - pub fn update_viewports( - &mut self, - imgui: &mut Context, - storage: &mut impl WinitPlatformViewportStorage, - ) { - // remove destroyed windows - storage.remove_windows(|id| !imgui.viewports().any(|vp| vp.id == id)); - - // handle new viewports - for viewport in imgui.viewports_mut() { - let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; - - if state.create { - storage.create_window(viewport.id, viewport.flags); - state.create = false; - } - } - - // handle other viewport events - storage.for_each(|id, wnd| { - let viewport = imgui.viewport_by_id_mut(id).unwrap(); - let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; - - if let Some(pos) = &state.set_pos { - let wnd_pos = wnd.outer_position().unwrap(); - let inner_pos = wnd.inner_position().unwrap(); - let decoration_size = [inner_pos.x - wnd_pos.x, inner_pos.y - wnd_pos.y]; - - wnd.set_outer_position(winit::dpi::LogicalPosition::new( - pos[0] - decoration_size[0] as f32, - pos[1] - decoration_size[1] as f32, - )); - state.set_pos = None; - } - if let Some(size) = &state.set_size { - wnd.set_inner_size(winit::dpi::LogicalSize::new(size[0], size[1])); - state.set_size = None; - } - if state.set_show { - wnd.set_visible(true); - state.set_show = false; - } - if state.set_focus { - wnd.focus_window(); - state.set_focus = false; - } - if let Some(title) = &state.set_title { - wnd.set_title(title); - state.set_title = None; - } - }); - } - /// Attaches the platform instance to a winit window. /// /// This function configures imgui-rs in the following ways: @@ -579,152 +358,6 @@ impl WinitPlatform { _ => (), } } - - #[cfg(feature = "viewports")] - pub fn handle_viewport_event( - &mut self, - imgui: &mut imgui::Context, - main_window: &Window, - storage: &mut impl WinitPlatformViewportStorage, - event: &Event, - ) { - if !imgui - .io() - .backend_flags - .contains(BackendFlags::PLATFORM_HAS_VIEWPORTS | BackendFlags::RENDERER_HAS_VIEWPORTS) - || !imgui - .io() - .config_flags - .contains(ConfigFlags::VIEWPORTS_ENABLE) - { - return; - } - - if let Event::WindowEvent { - window_id, - ref event, - } = *event - { - let (viewport, window) = if window_id == main_window.id() { - (imgui.main_viewport_mut(), main_window) - } else if let Some((viewport_id, window)) = storage.get_window(window_id) { - if let Some(viewport) = imgui.viewport_by_id_mut(viewport_id) { - (viewport, window) - } else { - return; - } - } else { - return; - }; - - let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; - - match *event { - WindowEvent::Resized(new_size) => { - state.size = [new_size.width as f32, new_size.height as f32]; - if new_size.width == 0 || new_size.height == 0 { - state.minimized = true; - } else { - state.minimized = false; - } - } - WindowEvent::Moved(_new_pos) => { - let pos = window.inner_position().unwrap(); - state.pos = [pos.x as f32, pos.y as f32]; - } - WindowEvent::CloseRequested => { - viewport.platform_request_close = true; - } - WindowEvent::Focused(focus) => { - state.focus = focus; - } - WindowEvent::CursorMoved { position, .. } => { - let wnd_pos = window.inner_position().unwrap(); - let pos = [ - wnd_pos.x as f32 + position.x as f32, - wnd_pos.y as f32 + position.y as f32, - ]; - imgui.io_mut().mouse_pos = pos; - } - WindowEvent::KeyboardInput { - input: - KeyboardInput { - virtual_keycode: Some(key), - state, - .. - }, - .. - } if window_id != main_window.id() => { - let io = imgui.io_mut(); - - let pressed = state == ElementState::Pressed; - io.keys_down[key as usize] = pressed; - - // This is a bit redundant here, but we'll leave it in. The OS occasionally - // fails to send modifiers keys, but it doesn't seem to send false-positives, - // so double checking isn't terrible in case some system *doesn't* send - // device events sometimes. - match key { - VirtualKeyCode::LShift | VirtualKeyCode::RShift => io.key_shift = pressed, - VirtualKeyCode::LControl | VirtualKeyCode::RControl => { - io.key_ctrl = pressed - } - VirtualKeyCode::LAlt | VirtualKeyCode::RAlt => io.key_alt = pressed, - VirtualKeyCode::LWin | VirtualKeyCode::RWin => io.key_super = pressed, - _ => (), - } - } - WindowEvent::ReceivedCharacter(ch) if window_id != main_window.id() => { - let io = imgui.io_mut(); - - // Exclude the backspace key ('\u{7f}'). Otherwise we will insert this char and then - // delete it. - if ch != '\u{7f}' { - io.add_input_character(ch) - } - } - WindowEvent::MouseWheel { - delta, - phase: TouchPhase::Moved, - .. - } if window_id != main_window.id() => match delta { - MouseScrollDelta::LineDelta(h, v) => { - let io = imgui.io_mut(); - io.mouse_wheel_h = h; - io.mouse_wheel = v; - } - MouseScrollDelta::PixelDelta(pos) => { - let io = imgui.io_mut(); - let pos = pos.to_logical::(self.hidpi_factor); - match pos.x.partial_cmp(&0.0) { - Some(Ordering::Greater) => io.mouse_wheel_h += 1.0, - Some(Ordering::Less) => io.mouse_wheel_h -= 1.0, - _ => (), - } - match pos.y.partial_cmp(&0.0) { - Some(Ordering::Greater) => io.mouse_wheel += 1.0, - Some(Ordering::Less) => io.mouse_wheel -= 1.0, - _ => (), - } - } - }, - WindowEvent::MouseInput { state, button, .. } if window_id != main_window.id() => { - let pressed = state == ElementState::Pressed; - match button { - MouseButton::Left => self.mouse_buttons[0].set(pressed), - MouseButton::Right => self.mouse_buttons[1].set(pressed), - MouseButton::Middle => self.mouse_buttons[2].set(pressed), - MouseButton::Other(idx @ 0..=4) => { - self.mouse_buttons[idx as usize].set(pressed) - } - _ => (), - } - } - _ => {} - } - } - } - fn handle_window_event(&mut self, io: &mut Io, window: &Window, event: &WindowEvent) { match *event { WindowEvent::Resized(physical_size) => { From 41e9d973f43583ffa442a629d2fb6cd94263972e Mon Sep 17 00:00:00 2001 From: Robin Date: Tue, 20 Dec 2022 13:32:26 +0100 Subject: [PATCH 25/42] Implemented basic viewports renderer --- .../examples/basic.rs | 27 ++- .../src/lib.rs | 161 ++++++++++++------ 2 files changed, 136 insertions(+), 52 deletions(-) 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, + ); + } + _ => {} } } } From 070f56f1d1ed6a86b0f63b97ccfa8128f306e77b Mon Sep 17 00:00:00 2001 From: Robin Date: Wed, 21 Dec 2022 19:44:45 +0100 Subject: [PATCH 26/42] Removed explicit version from shaders and not using new glsl features --- imgui-winit-glow-renderer-viewports/src/fragment_shader.glsl | 4 +--- imgui-winit-glow-renderer-viewports/src/vertex_shader.glsl | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/imgui-winit-glow-renderer-viewports/src/fragment_shader.glsl b/imgui-winit-glow-renderer-viewports/src/fragment_shader.glsl index b13bef2..b4f3964 100644 --- a/imgui-winit-glow-renderer-viewports/src/fragment_shader.glsl +++ b/imgui-winit-glow-renderer-viewports/src/fragment_shader.glsl @@ -1,9 +1,7 @@ -#version 450 core - in vec2 v2f_UV; in vec4 v2f_Color; -layout(location = 0) uniform sampler2D u_FontTexture; +uniform sampler2D u_FontTexture; layout(location = 0) out vec4 out_Color; diff --git a/imgui-winit-glow-renderer-viewports/src/vertex_shader.glsl b/imgui-winit-glow-renderer-viewports/src/vertex_shader.glsl index 4d74b81..50cff17 100644 --- a/imgui-winit-glow-renderer-viewports/src/vertex_shader.glsl +++ b/imgui-winit-glow-renderer-viewports/src/vertex_shader.glsl @@ -1,5 +1,3 @@ -#version 450 - layout(location = 0) in vec2 in_Position; layout(location = 1) in vec2 in_UV; layout(location = 2) in vec4 in_Color; From f430041018df73d0e1b2905875f4ddbb3854b66e Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Thu, 22 Dec 2022 14:44:26 +0100 Subject: [PATCH 27/42] Fixed crash on window docking on linux --- .../src/fragment_shader.glsl | 2 + .../src/lib.rs | 53 +++++++++++-------- .../src/vertex_shader.glsl | 2 + 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/imgui-winit-glow-renderer-viewports/src/fragment_shader.glsl b/imgui-winit-glow-renderer-viewports/src/fragment_shader.glsl index b4f3964..505432c 100644 --- a/imgui-winit-glow-renderer-viewports/src/fragment_shader.glsl +++ b/imgui-winit-glow-renderer-viewports/src/fragment_shader.glsl @@ -1,3 +1,5 @@ +#version 330 + in vec2 v2f_UV; in vec4 v2f_Color; diff --git a/imgui-winit-glow-renderer-viewports/src/lib.rs b/imgui-winit-glow-renderer-viewports/src/lib.rs index e5820ae..4b494e5 100644 --- a/imgui-winit-glow-renderer-viewports/src/lib.rs +++ b/imgui-winit-glow-renderer-viewports/src/lib.rs @@ -52,13 +52,15 @@ enum ViewportEvent { pub struct Renderer { gl_objects: GlObjects, glutin_config: Option, + /// The tuple members have to stay in exactly this order + /// to ensure that surface, context and window are dropped in this order extra_windows: HashMap< Id, ( - Window, - Option, - Surface, GlObjects, + Surface, + Option, + Window, ), >, event_queue: Rc>>, @@ -321,7 +323,7 @@ impl Renderer { (main_window, imgui.main_viewport_mut()) } else { if let Some((id, wnd)) = - self.extra_windows.iter().find_map(|(id, (wnd, _, _, _))| { + self.extra_windows.iter().find_map(|(id, (_, _, _, wnd))| { if wnd.id() == window_id { Some((*id, wnd)) } else { @@ -472,27 +474,27 @@ impl Renderer { self.extra_windows.remove(&id); } ViewportEvent::SetPos(id, pos) => { - if let Some((wnd, _, _, _)) = self.extra_windows.get(&id) { + if let Some((_, _, _, wnd)) = self.extra_windows.get(&id) { wnd.set_outer_position(PhysicalPosition::new(pos[0], pos[1])); } } ViewportEvent::SetSize(id, size) => { - if let Some((wnd, _, _, _)) = self.extra_windows.get(&id) { + if let Some((_, _, _, wnd)) = self.extra_windows.get(&id) { wnd.set_inner_size(PhysicalSize::new(size[0], size[1])); } } ViewportEvent::SetVisible(id) => { - if let Some((wnd, _, _, _)) = self.extra_windows.get(&id) { + if let Some((_, _, _, wnd)) = self.extra_windows.get(&id) { wnd.set_visible(true); } } ViewportEvent::SetFocus(id) => { - if let Some((wnd, _, _, _)) = self.extra_windows.get(&id) { + if let Some((_, _, _, wnd)) = self.extra_windows.get(&id) { wnd.focus_window(); } } ViewportEvent::SetTitle(id, title) => { - if let Some((wnd, _, _, _)) = self.extra_windows.get(&id) { + if let Some((_, _, _, wnd)) = self.extra_windows.get(&id) { wnd.set_title(&title); } } @@ -509,10 +511,10 @@ impl Renderer { glow: &glow::Context, ) -> Result< ( - Window, - Option, - Surface, GlObjects, + Surface, + Option, + Window, ), RendererError, > { @@ -572,10 +574,10 @@ impl Renderer { GlObjects::new(self.font_width, self.font_height, &self.font_pixels, glow)?; Ok(( - window, - Some(context.make_not_current().unwrap()), - surface, gl_objects, + surface, + Some(context.make_not_current().unwrap()), + window, )) } @@ -593,7 +595,7 @@ impl Renderer { glow: &glow::Context, imgui: &mut imgui::Context, ) -> Result<(), RendererError> { - for (id, (wnd, context, surface, gl_objects)) in &mut self.extra_windows { + for (id, (gl_objects, surface, context, wnd)) in &mut self.extra_windows { if let Some(viewport) = imgui.viewport_by_id(*id) { let current_context = context .take() @@ -689,12 +691,21 @@ impl Renderer { for cmd in list.commands() { match cmd { imgui::DrawCmd::Elements { count, cmd_params } => { - 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; + 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.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, diff --git a/imgui-winit-glow-renderer-viewports/src/vertex_shader.glsl b/imgui-winit-glow-renderer-viewports/src/vertex_shader.glsl index 50cff17..058c47b 100644 --- a/imgui-winit-glow-renderer-viewports/src/vertex_shader.glsl +++ b/imgui-winit-glow-renderer-viewports/src/vertex_shader.glsl @@ -1,3 +1,5 @@ +#version 330 + layout(location = 0) in vec2 in_Position; layout(location = 1) in vec2 in_UV; layout(location = 2) in vec4 in_Color; From 5d2e71ee556c5cc03ff201a9ab13a990604e9fe4 Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Fri, 23 Dec 2022 11:26:36 +0100 Subject: [PATCH 28/42] Fixed moving viewports messing up graphics --- imgui-winit-glow-renderer-viewports/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/imgui-winit-glow-renderer-viewports/src/lib.rs b/imgui-winit-glow-renderer-viewports/src/lib.rs index e5820ae..e9f2e51 100644 --- a/imgui-winit-glow-renderer-viewports/src/lib.rs +++ b/imgui-winit-glow-renderer-viewports/src/lib.rs @@ -346,6 +346,8 @@ impl Renderer { [new_size.width as f32, new_size.height as f32]; } + viewport.platform_request_resize = true; + if window_id == main_window.id() { imgui.io_mut().display_size = [new_size.width as f32, new_size.height as f32]; @@ -355,6 +357,8 @@ impl Renderer { let new_pos = window.inner_position().unwrap().cast::(); (*(viewport.platform_user_data.cast::())).pos = [new_pos.x as f32, new_pos.y as f32]; + + viewport.platform_request_move = true; }, winit::event::WindowEvent::CloseRequested if window_id != main_window.id() => { viewport.platform_request_close = true; From 9a48b78acd7e90238c1278895a101fa797b273dc Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Thu, 29 Dec 2022 14:07:26 +0100 Subject: [PATCH 29/42] Added basic cursor support --- .../examples/basic.rs | 2 ++ .../src/lib.rs | 34 ++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/imgui-winit-glow-renderer-viewports/examples/basic.rs b/imgui-winit-glow-renderer-viewports/examples/basic.rs index e8af25f..5d0f8c4 100644 --- a/imgui-winit-glow-renderer-viewports/examples/basic.rs +++ b/imgui-winit-glow-renderer-viewports/examples/basic.rs @@ -109,6 +109,8 @@ fn main() { ui.end_frame_early(); + renderer.prepare_render(&mut imgui, &window); + imgui.update_platform_windows(); renderer.update_viewports(&mut imgui, window_target, &glow).expect("Failed to update viewports"); diff --git a/imgui-winit-glow-renderer-viewports/src/lib.rs b/imgui-winit-glow-renderer-viewports/src/lib.rs index 5194431..644ac0c 100644 --- a/imgui-winit-glow-renderer-viewports/src/lib.rs +++ b/imgui-winit-glow-renderer-viewports/src/lib.rs @@ -23,7 +23,7 @@ use winit::{ dpi::{PhysicalPosition, PhysicalSize}, event::{DeviceEvent, ElementState, KeyboardInput, TouchPhase, VirtualKeyCode}, event_loop::EventLoopWindowTarget, - window::{Window, WindowBuilder}, + window::{Window, WindowBuilder, CursorIcon}, }; const VERTEX_SHADER: &str = include_str!("vertex_shader.glsl"); @@ -67,6 +67,7 @@ pub struct Renderer { font_width: u32, font_height: u32, font_pixels: Vec, + last_cursor: CursorIcon, } #[derive(Debug)] @@ -305,6 +306,7 @@ impl Renderer { font_width: font_tex.width, font_height: font_tex.height, font_pixels: font_tex.data.to_vec(), + last_cursor: CursorIcon::Default, }) } @@ -508,6 +510,36 @@ impl Renderer { Ok(()) } + fn to_winit_cursor(cursor: imgui::MouseCursor) -> winit::window::CursorIcon { + match cursor { + imgui::MouseCursor::Arrow => winit::window::CursorIcon::Default, + imgui::MouseCursor::TextInput => winit::window::CursorIcon::Text, + imgui::MouseCursor::ResizeAll => winit::window::CursorIcon::Move, + imgui::MouseCursor::ResizeNS => winit::window::CursorIcon::NsResize, + imgui::MouseCursor::ResizeEW => winit::window::CursorIcon::EwResize, + imgui::MouseCursor::ResizeNESW => winit::window::CursorIcon::NeswResize, + imgui::MouseCursor::ResizeNWSE => winit::window::CursorIcon::NwseResize, + imgui::MouseCursor::Hand => winit::window::CursorIcon::Hand, + imgui::MouseCursor::NotAllowed => winit::window::CursorIcon::NotAllowed, + } + } + + pub fn prepare_render(&mut self, imgui: &mut imgui::Context, main_window: &Window) { + if let Some(cursor) = imgui.mouse_cursor() { + let cursor = Self::to_winit_cursor(cursor); + + if self.last_cursor != cursor { + main_window.set_cursor_icon(cursor); + + for (_, (_, _, _, wnd)) in &self.extra_windows { + wnd.set_cursor_icon(cursor); + } + + self.last_cursor = cursor; + } + } + } + fn create_extra_window( &mut self, viewport: &mut imgui::Viewport, From 382cb74daae146549e13b2938d633d5a9acb8115 Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Thu, 29 Dec 2022 14:20:07 +0100 Subject: [PATCH 30/42] Added more fine-grained errors --- .../src/lib.rs | 52 ++++++++++++------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/imgui-winit-glow-renderer-viewports/src/lib.rs b/imgui-winit-glow-renderer-viewports/src/lib.rs index 644ac0c..4376506 100644 --- a/imgui-winit-glow-renderer-viewports/src/lib.rs +++ b/imgui-winit-glow-renderer-viewports/src/lib.rs @@ -31,10 +31,26 @@ const FRAGMENT_SHADER: &str = include_str!("fragment_shader.glsl"); #[derive(Debug, Error)] pub enum RendererError { - #[error("OpenGL object creation failed: {0}")] - GlObjectCreationError(String), - #[error("Failed to create glutin Display")] - GlutinDisplay, + #[error("OpenGL shader creation failed: {0}")] + GlShaderCreationFailed(String), + #[error("OpenGL program creation failed: {0}")] + GlProgramCreationFailed(String), + #[error("OpenGL texture creation failed: {0}")] + GlTextureCreationFailed(String), + #[error("OpenGL buffer creation failed: {0}")] + GlBufferCreationFailed(String), + #[error("OpenGL vertex array creation failed: {0}")] + GlVertexArrayCreationFailed(String), + #[error("Failed to create viewport window")] + WindowCreationFailed, + #[error("Failed to create viewport window context")] + WindowContextCreationFailed, + #[error("Failed to create viewport window surface")] + WindowSurfaceCreationFailed, + #[error("Failed to make viewport context current")] + MakeCurrentFailed, + #[error("Failed to make swap buffers on surface")] + SwapBuffersFailed, } #[derive(Debug)] @@ -89,7 +105,7 @@ impl GlObjects { let program = unsafe { let vertex_shader = glow .create_shader(glow::VERTEX_SHADER) - .map_err(|e| RendererError::GlObjectCreationError(e))?; + .map_err(|e| RendererError::GlShaderCreationFailed(e))?; glow.shader_source(vertex_shader, VERTEX_SHADER); glow.compile_shader(vertex_shader); assert!( @@ -99,7 +115,7 @@ impl GlObjects { let fragment_shader = glow .create_shader(glow::FRAGMENT_SHADER) - .map_err(|e| RendererError::GlObjectCreationError(e))?; + .map_err(|e| RendererError::GlShaderCreationFailed(e))?; glow.shader_source(fragment_shader, FRAGMENT_SHADER); glow.compile_shader(fragment_shader); assert!( @@ -109,7 +125,7 @@ impl GlObjects { let program = glow .create_program() - .map_err(|e| RendererError::GlObjectCreationError(e))?; + .map_err(|e| RendererError::GlProgramCreationFailed(e))?; glow.attach_shader(program, vertex_shader); glow.attach_shader(program, fragment_shader); glow.link_program(program); @@ -127,7 +143,7 @@ impl GlObjects { let font_texture = unsafe { let tex = glow .create_texture() - .map_err(|e| RendererError::GlObjectCreationError(e))?; + .map_err(|e| RendererError::GlTextureCreationFailed(e))?; glow.bind_texture(glow::TEXTURE_2D, Some(tex)); glow.tex_parameter_i32( glow::TEXTURE_2D, @@ -166,17 +182,17 @@ impl GlObjects { let vbo = unsafe { glow.create_buffer() - .map_err(|e| RendererError::GlObjectCreationError(e))? + .map_err(|e| RendererError::GlBufferCreationFailed(e))? }; let ibo = unsafe { glow.create_buffer() - .map_err(|e| RendererError::GlObjectCreationError(e))? + .map_err(|e| RendererError::GlBufferCreationFailed(e))? }; let vao = unsafe { let vao = glow .create_vertex_array() - .map_err(|e| RendererError::GlObjectCreationError(e))?; + .map_err(|e| RendererError::GlVertexArrayCreationFailed(e))?; glow.bind_vertex_array(Some(vao)); glow.bind_buffer(glow::ARRAY_BUFFER, Some(vbo)); @@ -563,7 +579,7 @@ impl Renderer { let window = if let Some(glutin_config) = &self.glutin_config { glutin_winit::finalize_window(window_target, window_builder, glutin_config) - .map_err(|_| RendererError::GlutinDisplay)? + .map_err(|_| RendererError::WindowCreationFailed)? } else { let template_builder = ConfigTemplateBuilder::new(); @@ -572,7 +588,7 @@ impl Renderer { .build(window_target, template_builder, |mut configs| { configs.next().unwrap() }) - .map_err(|_| RendererError::GlutinDisplay)?; + .map_err(|_| RendererError::WindowCreationFailed)?; self.glutin_config = Some(cfg); @@ -587,7 +603,7 @@ impl Renderer { glutin_config .display() .create_context(&glutin_config, &context_attribs) - .map_err(|_| RendererError::GlutinDisplay)? + .map_err(|_| RendererError::WindowContextCreationFailed)? }; let surface_attribs = SurfaceAttributesBuilder::::new().build( @@ -599,12 +615,12 @@ impl Renderer { glutin_config .display() .create_window_surface(glutin_config, &surface_attribs) - .map_err(|_| RendererError::GlutinDisplay)? + .map_err(|_| RendererError::WindowSurfaceCreationFailed)? }; let context = context .make_current(&surface) - .map_err(|_| RendererError::GlutinDisplay)?; + .map_err(|_| RendererError::MakeCurrentFailed)?; let gl_objects = GlObjects::new(self.font_width, self.font_height, &self.font_pixels, glow)?; @@ -637,7 +653,7 @@ impl Renderer { .take() .unwrap() .make_current(surface) - .map_err(|_| RendererError::GlutinDisplay)?; + .map_err(|_| RendererError::MakeCurrentFailed)?; unsafe { glow.disable(glow::SCISSOR_TEST); @@ -646,7 +662,7 @@ impl Renderer { Self::render_window(wnd, glow, viewport.draw_data(), gl_objects)?; surface .swap_buffers(¤t_context) - .map_err(|_| RendererError::GlutinDisplay)?; + .map_err(|_| RendererError::SwapBuffersFailed)?; *context = Some(current_context.make_not_current().unwrap()); } From 45b9d275574ee91de4341ee28522acb5522b7a8a Mon Sep 17 00:00:00 2001 From: Robin Date: Sat, 14 Jan 2023 19:28:59 +0100 Subject: [PATCH 31/42] Adapted Viewport structs to new ImGui Version --- imgui-winit-glow-renderer-viewports/src/lib.rs | 2 +- imgui/src/platform_io.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/imgui-winit-glow-renderer-viewports/src/lib.rs b/imgui-winit-glow-renderer-viewports/src/lib.rs index 4376506..7e6fd73 100644 --- a/imgui-winit-glow-renderer-viewports/src/lib.rs +++ b/imgui-winit-glow-renderer-viewports/src/lib.rs @@ -250,7 +250,7 @@ impl Renderer { io[Key::Space] = VirtualKeyCode::Space as _; io[Key::Enter] = VirtualKeyCode::Return as _; io[Key::Escape] = VirtualKeyCode::Escape as _; - io[Key::KeyPadEnter] = VirtualKeyCode::NumpadEnter as _; + io[Key::KeypadEnter] = VirtualKeyCode::NumpadEnter as _; io[Key::A] = VirtualKeyCode::A as _; io[Key::C] = VirtualKeyCode::C as _; io[Key::V] = VirtualKeyCode::V as _; diff --git a/imgui/src/platform_io.rs b/imgui/src/platform_io.rs index 3c9b122..72d040a 100644 --- a/imgui/src/platform_io.rs +++ b/imgui/src/platform_io.rs @@ -29,7 +29,6 @@ pub struct PlatformIo { pub(crate) platform_swap_buffers: Option, pub(crate) platform_get_window_dpi_scale: Option f32>, pub(crate) platform_on_changed_viewport: Option, - pub(crate) platform_set_ime_input_pos: Option, pub(crate) platform_create_vk_surface: Option c_int>, @@ -87,7 +86,6 @@ fn test_platform_io_memory_layout() { assert_field_offset!(platform_swap_buffers, Platform_SwapBuffers); assert_field_offset!(platform_get_window_dpi_scale, Platform_GetWindowDpiScale); assert_field_offset!(platform_on_changed_viewport, Platform_OnChangedViewport); - assert_field_offset!(platform_set_ime_input_pos, Platform_SetImeInputPos); assert_field_offset!(platform_create_vk_surface, Platform_CreateVkSurface); assert_field_offset!(renderer_create_window, Renderer_CreateWindow); @@ -446,6 +444,7 @@ pub struct Viewport { pub platform_user_data: *mut c_void, pub platform_handle: *mut c_void, pub platform_handle_raw: *mut c_void, + pub platform_window_created: bool, pub platform_request_move: bool, pub platform_request_resize: bool, pub platform_request_close: bool, @@ -494,6 +493,7 @@ fn test_viewport_memory_layout() { assert_field_offset!(platform_user_data, PlatformUserData); assert_field_offset!(platform_handle, PlatformHandle); assert_field_offset!(platform_handle_raw, PlatformHandleRaw); + assert_field_offset!(platform_window_created, PlatformWindowCreated); assert_field_offset!(platform_request_move, PlatformRequestMove); assert_field_offset!(platform_request_resize, PlatformRequestResize); assert_field_offset!(platform_request_close, PlatformRequestClose); From 654aabac713f1cc2c60f5cac3a54d18482012cb7 Mon Sep 17 00:00:00 2001 From: Robin Date: Sat, 21 Jan 2023 19:30:16 +0100 Subject: [PATCH 32/42] viewports renderer should now work with viewports disabled --- .../src/lib.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/imgui-winit-glow-renderer-viewports/src/lib.rs b/imgui-winit-glow-renderer-viewports/src/lib.rs index 7e6fd73..86873eb 100644 --- a/imgui-winit-glow-renderer-viewports/src/lib.rs +++ b/imgui-winit-glow-renderer-viewports/src/lib.rs @@ -16,7 +16,7 @@ use glutin::{ surface::{GlSurface, Surface, SurfaceAttributesBuilder, WindowSurface}, }; use glutin_winit::DisplayBuilder; -use imgui::{BackendFlags, Id, Key, ViewportFlags}; +use imgui::{BackendFlags, Id, Key, ViewportFlags, ConfigFlags}; use raw_window_handle::HasRawWindowHandle; use thiserror::Error; use winit::{ @@ -401,11 +401,18 @@ impl Renderer { imgui.io_mut().keys_down[key as usize] = true; } winit::event::WindowEvent::CursorMoved { position, .. } => { - 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, - ]; + if imgui.io().config_flags.contains(ConfigFlags::VIEWPORTS_ENABLE) { + 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, + ]; + } else { + imgui.io_mut().mouse_pos = [ + position.x as f32, + position.y as f32, + ]; + } } winit::event::WindowEvent::MouseWheel { delta, From 5f4cbcdc1636daf454c7296339b5c713dd1d4892 Mon Sep 17 00:00:00 2001 From: Robin Date: Sat, 21 Jan 2023 19:51:51 +0100 Subject: [PATCH 33/42] Renderer now disables viewports on wayland --- .../src/lib.rs | 97 +++++++++++-------- 1 file changed, 58 insertions(+), 39 deletions(-) diff --git a/imgui-winit-glow-renderer-viewports/src/lib.rs b/imgui-winit-glow-renderer-viewports/src/lib.rs index 86873eb..202ea7c 100644 --- a/imgui-winit-glow-renderer-viewports/src/lib.rs +++ b/imgui-winit-glow-renderer-viewports/src/lib.rs @@ -16,14 +16,14 @@ use glutin::{ surface::{GlSurface, Surface, SurfaceAttributesBuilder, WindowSurface}, }; use glutin_winit::DisplayBuilder; -use imgui::{BackendFlags, Id, Key, ViewportFlags, ConfigFlags}; -use raw_window_handle::HasRawWindowHandle; +use imgui::{BackendFlags, ConfigFlags, Id, Key, ViewportFlags}; +use raw_window_handle::{HasRawWindowHandle, RawWindowHandle}; use thiserror::Error; use winit::{ dpi::{PhysicalPosition, PhysicalSize}, event::{DeviceEvent, ElementState, KeyboardInput, TouchPhase, VirtualKeyCode}, event_loop::EventLoopWindowTarget, - window::{Window, WindowBuilder, CursorIcon}, + window::{CursorIcon, Window, WindowBuilder}, }; const VERTEX_SHADER: &str = include_str!("vertex_shader.glsl"); @@ -226,12 +226,21 @@ impl Renderer { ) -> Result { let io = imgui.io_mut(); + // there is no good way to handle viewports on wayland, + // so we disable them + match main_window.raw_window_handle() { + RawWindowHandle::Wayland(_) => {} + _ => { + io.backend_flags + .insert(BackendFlags::PLATFORM_HAS_VIEWPORTS); + io.backend_flags + .insert(BackendFlags::RENDERER_HAS_VIEWPORTS); + } + } + io.backend_flags.insert(BackendFlags::HAS_MOUSE_CURSORS); io.backend_flags.insert(BackendFlags::HAS_SET_MOUSE_POS); - io.backend_flags - .insert(BackendFlags::PLATFORM_HAS_VIEWPORTS); - io.backend_flags - .insert(BackendFlags::RENDERER_HAS_VIEWPORTS); + io.backend_flags .insert(BackendFlags::RENDERER_HAS_VTX_OFFSET); @@ -262,37 +271,42 @@ impl Renderer { io.display_size = [window_size.width, window_size.height]; io.display_framebuffer_scale = [1.0, 1.0]; - let viewport = imgui.main_viewport_mut(); + if io + .backend_flags + .contains(BackendFlags::RENDERER_HAS_VIEWPORTS) + { + let viewport = imgui.main_viewport_mut(); - let main_pos = main_window.inner_position().unwrap().cast::(); + let main_pos = main_window.inner_position().unwrap().cast::(); - viewport.pos = [main_pos.x, main_pos.y]; - viewport.work_pos = viewport.pos; - viewport.size = [window_size.width, window_size.height]; - viewport.work_size = viewport.size; - viewport.dpi_scale = 1.0; - viewport.platform_user_data = Box::into_raw(Box::new(ViewportData { - pos: [main_pos.x, main_pos.y], - size: [window_size.width, window_size.height], - focus: true, - minimized: false, - })) - .cast(); + viewport.pos = [main_pos.x, main_pos.y]; + viewport.work_pos = viewport.pos; + viewport.size = [window_size.width, window_size.height]; + viewport.work_size = viewport.size; + viewport.dpi_scale = 1.0; + viewport.platform_user_data = Box::into_raw(Box::new(ViewportData { + pos: [main_pos.x, main_pos.y], + size: [window_size.width, window_size.height], + focus: true, + minimized: false, + })) + .cast(); - let mut monitors = Vec::new(); - for monitor in main_window.available_monitors() { - monitors.push(imgui::PlatformMonitor { - main_pos: [monitor.position().x as f32, monitor.position().y as f32], - main_size: [monitor.size().width as f32, monitor.size().height as f32], - work_pos: [monitor.position().x as f32, monitor.position().y as f32], - work_size: [monitor.size().width as f32, monitor.size().height as f32], - dpi_scale: 1.0, - }); + let mut monitors = Vec::new(); + for monitor in main_window.available_monitors() { + monitors.push(imgui::PlatformMonitor { + main_pos: [monitor.position().x as f32, monitor.position().y as f32], + main_size: [monitor.size().width as f32, monitor.size().height as f32], + work_pos: [monitor.position().x as f32, monitor.position().y as f32], + work_size: [monitor.size().width as f32, monitor.size().height as f32], + dpi_scale: 1.0, + }); + } + imgui + .platform_io_mut() + .monitors + .replace_from_slice(&monitors); } - imgui - .platform_io_mut() - .monitors - .replace_from_slice(&monitors); imgui.set_platform_name(Some(format!( "imgui-winit-glow-renderer-viewports {}", @@ -401,17 +415,22 @@ impl Renderer { imgui.io_mut().keys_down[key as usize] = true; } winit::event::WindowEvent::CursorMoved { position, .. } => { - if imgui.io().config_flags.contains(ConfigFlags::VIEWPORTS_ENABLE) { + if imgui + .io() + .config_flags + .contains(ConfigFlags::VIEWPORTS_ENABLE) + && imgui + .io() + .backend_flags + .contains(BackendFlags::RENDERER_HAS_VIEWPORTS) + { 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, ]; } else { - imgui.io_mut().mouse_pos = [ - position.x as f32, - position.y as f32, - ]; + imgui.io_mut().mouse_pos = [position.x as f32, position.y as f32]; } } winit::event::WindowEvent::MouseWheel { From a84610ee03b8ba4c9661eaa4b53de99312cd2529 Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Sat, 21 Jan 2023 20:04:59 +0100 Subject: [PATCH 34/42] Fixed renderer on wayland --- .../examples/basic.rs | 3 + .../src/lib.rs | 65 ++++++++----------- 2 files changed, 31 insertions(+), 37 deletions(-) diff --git a/imgui-winit-glow-renderer-viewports/examples/basic.rs b/imgui-winit-glow-renderer-viewports/examples/basic.rs index 5d0f8c4..11dfd99 100644 --- a/imgui-winit-glow-renderer-viewports/examples/basic.rs +++ b/imgui-winit-glow-renderer-viewports/examples/basic.rs @@ -94,6 +94,9 @@ fn main() { winit::event::Event::WindowEvent { window_id, event: WindowEvent::CloseRequested } if window_id == window.id() => { control_flow.set_exit(); }, + winit::event::Event::WindowEvent { window_id, event: WindowEvent::Resized(new_size) } if window_id == window.id() => { + surface.resize(&context, NonZeroU32::new(new_size.width).unwrap(), NonZeroU32::new(new_size.height).unwrap()); + }, winit::event::Event::MainEventsCleared => { window.request_redraw(); }, diff --git a/imgui-winit-glow-renderer-viewports/src/lib.rs b/imgui-winit-glow-renderer-viewports/src/lib.rs index 202ea7c..a46195d 100644 --- a/imgui-winit-glow-renderer-viewports/src/lib.rs +++ b/imgui-winit-glow-renderer-viewports/src/lib.rs @@ -271,42 +271,37 @@ impl Renderer { io.display_size = [window_size.width, window_size.height]; io.display_framebuffer_scale = [1.0, 1.0]; - if io - .backend_flags - .contains(BackendFlags::RENDERER_HAS_VIEWPORTS) - { - let viewport = imgui.main_viewport_mut(); + let viewport = imgui.main_viewport_mut(); - let main_pos = main_window.inner_position().unwrap().cast::(); + let main_pos = main_window.inner_position().unwrap_or_default().cast::(); - viewport.pos = [main_pos.x, main_pos.y]; - viewport.work_pos = viewport.pos; - viewport.size = [window_size.width, window_size.height]; - viewport.work_size = viewport.size; - viewport.dpi_scale = 1.0; - viewport.platform_user_data = Box::into_raw(Box::new(ViewportData { - pos: [main_pos.x, main_pos.y], - size: [window_size.width, window_size.height], - focus: true, - minimized: false, - })) - .cast(); + viewport.pos = [main_pos.x, main_pos.y]; + viewport.work_pos = viewport.pos; + viewport.size = [window_size.width, window_size.height]; + viewport.work_size = viewport.size; + viewport.dpi_scale = 1.0; + viewport.platform_user_data = Box::into_raw(Box::new(ViewportData { + pos: [main_pos.x, main_pos.y], + size: [window_size.width, window_size.height], + focus: true, + minimized: false, + })) + .cast(); - let mut monitors = Vec::new(); - for monitor in main_window.available_monitors() { - monitors.push(imgui::PlatformMonitor { - main_pos: [monitor.position().x as f32, monitor.position().y as f32], - main_size: [monitor.size().width as f32, monitor.size().height as f32], - work_pos: [monitor.position().x as f32, monitor.position().y as f32], - work_size: [monitor.size().width as f32, monitor.size().height as f32], - dpi_scale: 1.0, - }); - } - imgui - .platform_io_mut() - .monitors - .replace_from_slice(&monitors); + let mut monitors = Vec::new(); + for monitor in main_window.available_monitors() { + monitors.push(imgui::PlatformMonitor { + main_pos: [monitor.position().x as f32, monitor.position().y as f32], + main_size: [monitor.size().width as f32, monitor.size().height as f32], + work_pos: [monitor.position().x as f32, monitor.position().y as f32], + work_size: [monitor.size().width as f32, monitor.size().height as f32], + dpi_scale: 1.0, + }); } + imgui + .platform_io_mut() + .monitors + .replace_from_slice(&monitors); imgui.set_platform_name(Some(format!( "imgui-winit-glow-renderer-viewports {}", @@ -419,12 +414,8 @@ impl Renderer { .io() .config_flags .contains(ConfigFlags::VIEWPORTS_ENABLE) - && imgui - .io() - .backend_flags - .contains(BackendFlags::RENDERER_HAS_VIEWPORTS) { - let window_pos = window.inner_position().unwrap().cast::(); + let window_pos = window.inner_position().unwrap_or_default().cast::(); imgui.io_mut().mouse_pos = [ position.x as f32 + window_pos.x, position.y as f32 + window_pos.y, From 5528eef52dfc4cc942764369b7de4f9726868458 Mon Sep 17 00:00:00 2001 From: Robin Date: Sat, 21 Jan 2023 20:10:19 +0100 Subject: [PATCH 35/42] cargo fmt --- .../examples/basic.rs | 54 +++++++++++++------ .../src/lib.rs | 8 ++- 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/imgui-winit-glow-renderer-viewports/examples/basic.rs b/imgui-winit-glow-renderer-viewports/examples/basic.rs index 11dfd99..b49e70f 100644 --- a/imgui-winit-glow-renderer-viewports/examples/basic.rs +++ b/imgui-winit-glow-renderer-viewports/examples/basic.rs @@ -5,14 +5,16 @@ use glutin::{ config::ConfigTemplateBuilder, context::ContextAttributesBuilder, display::GetGlDisplay, - prelude::{GlDisplay, NotCurrentGlContextSurfaceAccessor, PossiblyCurrentContextGlSurfaceAccessor}, - surface::{SurfaceAttributesBuilder, WindowSurface, GlSurface}, + prelude::{ + GlDisplay, NotCurrentGlContextSurfaceAccessor, PossiblyCurrentContextGlSurfaceAccessor, + }, + surface::{GlSurface, SurfaceAttributesBuilder, WindowSurface}, }; 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, event::WindowEvent}; +use winit::{dpi::LogicalSize, event::WindowEvent, event_loop::EventLoop, window::WindowBuilder}; fn main() { let event_loop = EventLoop::new(); @@ -90,16 +92,26 @@ fn main() { 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() => { + } + winit::event::Event::WindowEvent { + window_id, + event: WindowEvent::CloseRequested, + } if window_id == window.id() => { control_flow.set_exit(); - }, - winit::event::Event::WindowEvent { window_id, event: WindowEvent::Resized(new_size) } if window_id == window.id() => { - surface.resize(&context, NonZeroU32::new(new_size.width).unwrap(), NonZeroU32::new(new_size.height).unwrap()); - }, + } + winit::event::Event::WindowEvent { + window_id, + event: WindowEvent::Resized(new_size), + } if window_id == window.id() => { + surface.resize( + &context, + NonZeroU32::new(new_size.width).unwrap(), + NonZeroU32::new(new_size.height).unwrap(), + ); + } winit::event::Event::MainEventsCleared => { window.request_redraw(); - }, + } winit::event::Event::RedrawRequested(_) => { let ui = imgui.frame(); @@ -115,7 +127,9 @@ fn main() { renderer.prepare_render(&mut imgui, &window); imgui.update_platform_windows(); - renderer.update_viewports(&mut imgui, window_target, &glow).expect("Failed to update viewports"); + renderer + .update_viewports(&mut imgui, window_target, &glow) + .expect("Failed to update viewports"); let draw_data = imgui.render(); @@ -130,13 +144,19 @@ fn main() { glow.clear(glow::COLOR_BUFFER_BIT); } - renderer.render(&window, &glow, draw_data).expect("Failed to render main viewport"); - - surface.swap_buffers(&context).expect("Failed to swap buffers"); + renderer + .render(&window, &glow, draw_data) + .expect("Failed to render main viewport"); - renderer.render_viewports(&glow, &mut imgui).expect("Failed to render viewports"); - }, - _ => {}, + surface + .swap_buffers(&context) + .expect("Failed to swap buffers"); + + renderer + .render_viewports(&glow, &mut imgui) + .expect("Failed to render viewports"); + } + _ => {} } }); } diff --git a/imgui-winit-glow-renderer-viewports/src/lib.rs b/imgui-winit-glow-renderer-viewports/src/lib.rs index a46195d..f793651 100644 --- a/imgui-winit-glow-renderer-viewports/src/lib.rs +++ b/imgui-winit-glow-renderer-viewports/src/lib.rs @@ -273,7 +273,10 @@ impl Renderer { let viewport = imgui.main_viewport_mut(); - let main_pos = main_window.inner_position().unwrap_or_default().cast::(); + let main_pos = main_window + .inner_position() + .unwrap_or_default() + .cast::(); viewport.pos = [main_pos.x, main_pos.y]; viewport.work_pos = viewport.pos; @@ -415,7 +418,8 @@ impl Renderer { .config_flags .contains(ConfigFlags::VIEWPORTS_ENABLE) { - let window_pos = window.inner_position().unwrap_or_default().cast::(); + let window_pos = + window.inner_position().unwrap_or_default().cast::(); imgui.io_mut().mouse_pos = [ position.x as f32 + window_pos.x, position.y as f32 + window_pos.y, From bc9cb1c24694ff375d41c369a1061679c2e442fb Mon Sep 17 00:00:00 2001 From: Robin Date: Sat, 21 Jan 2023 20:44:22 +0100 Subject: [PATCH 36/42] viewports renderer now backups OpenGL state --- .../src/lib.rs | 131 +++++++++++++++++- 1 file changed, 130 insertions(+), 1 deletion(-) diff --git a/imgui-winit-glow-renderer-viewports/src/lib.rs b/imgui-winit-glow-renderer-viewports/src/lib.rs index f793651..5aab89d 100644 --- a/imgui-winit-glow-renderer-viewports/src/lib.rs +++ b/imgui-winit-glow-renderer-viewports/src/lib.rs @@ -218,6 +218,132 @@ impl GlObjects { } } +#[derive(Debug)] +struct GlStateBackup { + viewport: [i32; 4], + blend_enabled: bool, + blend_func_src: i32, + blend_func_dst: i32, + scissor_enabled: bool, + scissor: [i32; 4], + vao: i32, + vbo: i32, + ibo: i32, + active_texture: i32, + texture: i32, + program: i32, +} + +impl GlStateBackup { + fn backup(context: &glow::Context) -> Self { + unsafe { + let mut viewport = [0; 4]; + context.get_parameter_i32_slice(glow::VIEWPORT, &mut viewport); + + let blend_enabled = context.is_enabled(glow::BLEND); + let blend_func_src = context.get_parameter_i32(glow::BLEND_SRC); + let blend_func_dst = context.get_parameter_i32(glow::BLEND_DST); + + let scissor_enabled = context.is_enabled(glow::SCISSOR_TEST); + let mut scissor = [0; 4]; + context.get_parameter_i32_slice(glow::SCISSOR_BOX, &mut scissor); + + let vao = context.get_parameter_i32(glow::VERTEX_ARRAY_BINDING); + let vbo = context.get_parameter_i32(glow::ARRAY_BUFFER_BINDING); + let ibo = context.get_parameter_i32(glow::ELEMENT_ARRAY_BUFFER_BINDING); + + let active_texture = context.get_parameter_i32(glow::ACTIVE_TEXTURE); + context.active_texture(0); + let texture = context.get_parameter_i32(glow::TEXTURE_BINDING_2D); + + let program = context.get_parameter_i32(glow::CURRENT_PROGRAM); + + Self { + viewport, + blend_enabled, + blend_func_src, + blend_func_dst, + scissor_enabled, + scissor, + vao, + vbo, + ibo, + active_texture, + texture, + program, + } + } + } + + fn restore(&self, context: &glow::Context) { + unsafe { + context.viewport( + self.viewport[0], + self.viewport[1], + self.viewport[2], + self.viewport[3], + ); + + Self::enable(context, glow::BLEND, self.blend_enabled); + context.blend_func(self.blend_func_src as _, self.blend_func_dst as _); + + Self::enable(context, glow::SCISSOR_TEST, self.scissor_enabled); + context.scissor( + self.scissor[0], + self.scissor[1], + self.scissor[2], + self.scissor[3], + ); + + if self.vao != 0 { + let vao = std::mem::transmute(self.vao); + context.bind_vertex_array(Some(vao)); + } else { + context.bind_vertex_array(None); + } + + if self.vbo != 0 { + let vbo = std::mem::transmute(self.vbo); + context.bind_buffer(glow::ARRAY_BUFFER, Some(vbo)); + } else { + context.bind_buffer(glow::ARRAY_BUFFER, None); + } + + if self.ibo != 0 { + let ibo = std::mem::transmute(self.ibo); + context.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(ibo)); + } else { + context.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, None); + } + + if self.texture != 0 { + let texture = std::mem::transmute(self.texture); + context.bind_texture(glow::TEXTURE_2D, Some(texture)); + } else { + context.bind_texture(glow::TEXTURE_2D, None); + } + context.active_texture(self.active_texture as _); + + if self.program != 0 { + let program = std::mem::transmute(self.program); + context.use_program(Some(program)); + } else { + context.use_program(None); + } + } + } + + fn enable(context: &glow::Context, feature: u32, value: bool) { + unsafe { + if value { + context.enable(feature); + } else { + context.disable(feature); + } + } + } +} + impl Renderer { pub fn new( imgui: &mut imgui::Context, @@ -660,7 +786,10 @@ impl Renderer { glow: &glow::Context, draw_data: &imgui::DrawData, ) -> Result<(), RendererError> { - Self::render_window(main_window, glow, draw_data, &self.gl_objects) + let backup = GlStateBackup::backup(glow); + let res = Self::render_window(main_window, glow, draw_data, &self.gl_objects); + backup.restore(glow); + res } pub fn render_viewports( From 29b23ec5dc2d5ba190da9efb719d85f20de3bad2 Mon Sep 17 00:00:00 2001 From: Robin Date: Sat, 21 Jan 2023 20:48:18 +0100 Subject: [PATCH 37/42] Bumped everything to MSRV 1.60 --- .github/workflows/ci.yml | 4 ++-- README.markdown | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e845083..6a730d8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: strategy: matrix: - rust: ["1.57"] + rust: ["1.60"] env: RUSTFLAGS: -D warnings @@ -81,7 +81,7 @@ jobs: matrix: rust: - stable - - "1.57" + - "1.60" os: - ubuntu-latest - macos-latest diff --git a/README.markdown b/README.markdown index af81b54..dcf13f3 100644 --- a/README.markdown +++ b/README.markdown @@ -60,7 +60,7 @@ be applicable to usage with any backend/renderer. ## Minimum Support Rust Version (MSRV) -The MSRV for `imgui-rs` and all of the backend crates is **1.57**. We update our MSRV periodically, and issue a minor bump for it. +The MSRV for `imgui-rs` and all of the backend crates is **1.60**. We update our MSRV periodically, and issue a minor bump for it. ## Choosing a backend platform and a renderer From 3ac84559fa6c500be9964ff469c34ba442f680c8 Mon Sep 17 00:00:00 2001 From: Robin Date: Sat, 21 Jan 2023 21:05:37 +0100 Subject: [PATCH 38/42] viewports renderer now uses event-based io --- .../src/lib.rs | 203 ++++++++++++++---- 1 file changed, 156 insertions(+), 47 deletions(-) diff --git a/imgui-winit-glow-renderer-viewports/src/lib.rs b/imgui-winit-glow-renderer-viewports/src/lib.rs index 5aab89d..9ed5c9e 100644 --- a/imgui-winit-glow-renderer-viewports/src/lib.rs +++ b/imgui-winit-glow-renderer-viewports/src/lib.rs @@ -16,7 +16,7 @@ use glutin::{ surface::{GlSurface, Surface, SurfaceAttributesBuilder, WindowSurface}, }; use glutin_winit::DisplayBuilder; -use imgui::{BackendFlags, ConfigFlags, Id, Key, ViewportFlags}; +use imgui::{BackendFlags, ConfigFlags, Id, Key, MouseButton, ViewportFlags}; use raw_window_handle::{HasRawWindowHandle, RawWindowHandle}; use thiserror::Error; use winit::{ @@ -370,29 +370,6 @@ impl Renderer { io.backend_flags .insert(BackendFlags::RENDERER_HAS_VTX_OFFSET); - io[Key::Tab] = VirtualKeyCode::Tab as _; - io[Key::LeftArrow] = VirtualKeyCode::Left as _; - io[Key::RightArrow] = VirtualKeyCode::Right as _; - io[Key::UpArrow] = VirtualKeyCode::Up as _; - io[Key::DownArrow] = VirtualKeyCode::Down as _; - io[Key::PageUp] = VirtualKeyCode::PageUp as _; - io[Key::PageDown] = VirtualKeyCode::PageDown as _; - io[Key::Home] = VirtualKeyCode::Home as _; - io[Key::End] = VirtualKeyCode::End as _; - io[Key::Insert] = VirtualKeyCode::Insert as _; - io[Key::Delete] = VirtualKeyCode::Delete as _; - io[Key::Backspace] = VirtualKeyCode::Back as _; - io[Key::Space] = VirtualKeyCode::Space as _; - io[Key::Enter] = VirtualKeyCode::Return as _; - io[Key::Escape] = VirtualKeyCode::Escape as _; - io[Key::KeypadEnter] = VirtualKeyCode::NumpadEnter as _; - io[Key::A] = VirtualKeyCode::A as _; - io[Key::C] = VirtualKeyCode::C as _; - io[Key::V] = VirtualKeyCode::V as _; - io[Key::X] = VirtualKeyCode::X as _; - io[Key::Y] = VirtualKeyCode::Y as _; - io[Key::Z] = VirtualKeyCode::Z as _; - let window_size = main_window.inner_size().cast::(); io.display_size = [window_size.width, window_size.height]; io.display_framebuffer_scale = [1.0, 1.0]; @@ -536,7 +513,19 @@ impl Renderer { }, .. } => { - imgui.io_mut().keys_down[key as usize] = true; + if let Some(key) = to_imgui_key(key) { + imgui.io_mut().add_key_event(key, true); + } + } + winit::event::WindowEvent::ModifiersChanged(modifiers) => { + imgui + .io_mut() + .add_key_event(Key::ModShift, modifiers.shift()); + imgui.io_mut().add_key_event(Key::ModCtrl, modifiers.ctrl()); + imgui.io_mut().add_key_event(Key::ModAlt, modifiers.alt()); + imgui + .io_mut() + .add_key_event(Key::ModSuper, modifiers.logo()); } winit::event::WindowEvent::CursorMoved { position, .. } => { if imgui @@ -546,12 +535,14 @@ impl Renderer { { let window_pos = window.inner_position().unwrap_or_default().cast::(); - imgui.io_mut().mouse_pos = [ + imgui.io_mut().add_mouse_pos_event([ position.x as f32 + window_pos.x, position.y as f32 + window_pos.y, - ]; + ]); } else { - imgui.io_mut().mouse_pos = [position.x as f32, position.y as f32]; + imgui + .io_mut() + .add_mouse_pos_event([position.x as f32, position.y as f32]); } } winit::event::WindowEvent::MouseWheel { @@ -560,43 +551,31 @@ impl Renderer { .. } => match delta { winit::event::MouseScrollDelta::LineDelta(h, v) => { - imgui.io_mut().mouse_wheel_h = h; - imgui.io_mut().mouse_wheel = v; + imgui.io_mut().add_mouse_wheel_event([h, v]); } winit::event::MouseScrollDelta::PixelDelta(pos) => { - imgui.io_mut().mouse_wheel_h += if pos.x > 0.0 { + let h = if pos.x > 0.0 { 1.0 } else if pos.x < 0.0 { -1.0 } else { 0.0 }; - imgui.io_mut().mouse_wheel += if pos.y > 0.0 { + let v = if pos.y > 0.0 { 1.0 } else if pos.y < 0.0 { -1.0 } else { 0.0 }; + imgui.io_mut().add_mouse_wheel_event([h, v]); } }, winit::event::WindowEvent::MouseInput { state, button, .. } => { let state = state == ElementState::Pressed; - match button { - winit::event::MouseButton::Left => { - imgui.io_mut().mouse_down[0] = state; - } - winit::event::MouseButton::Right => { - imgui.io_mut().mouse_down[1] = state; - } - winit::event::MouseButton::Middle => { - imgui.io_mut().mouse_down[2] = state; - } - winit::event::MouseButton::Other(index @ 0..=4) => { - imgui.io_mut().mouse_down[index as usize] = state; - } - _ => {} + if let Some(button) = to_imgui_mouse_button(button) { + imgui.io_mut().add_mouse_button_event(button, state); } } _ => {} @@ -611,7 +590,9 @@ impl Renderer { }), .. } => { - imgui.io_mut().keys_down[key as usize] = false; + if let Some(key) = to_imgui_key(key) { + imgui.io_mut().add_key_event(key, false); + } } _ => {} } @@ -1041,3 +1022,131 @@ impl imgui::RendererViewportBackend for RendererBackend { fn swap_buffers(&mut self, _viewport: &mut imgui::Viewport) {} } + +fn to_imgui_key(keycode: VirtualKeyCode) -> Option { + match keycode { + VirtualKeyCode::Tab => Some(Key::Tab), + VirtualKeyCode::Left => Some(Key::LeftArrow), + VirtualKeyCode::Right => Some(Key::RightArrow), + VirtualKeyCode::Up => Some(Key::UpArrow), + VirtualKeyCode::Down => Some(Key::DownArrow), + VirtualKeyCode::PageUp => Some(Key::PageUp), + VirtualKeyCode::PageDown => Some(Key::PageDown), + VirtualKeyCode::Home => Some(Key::Home), + VirtualKeyCode::End => Some(Key::End), + VirtualKeyCode::Insert => Some(Key::Insert), + VirtualKeyCode::Delete => Some(Key::Delete), + VirtualKeyCode::Back => Some(Key::Backspace), + VirtualKeyCode::Space => Some(Key::Space), + VirtualKeyCode::Return => Some(Key::Enter), + VirtualKeyCode::Escape => Some(Key::Escape), + VirtualKeyCode::LControl => Some(Key::LeftCtrl), + VirtualKeyCode::LShift => Some(Key::LeftShift), + VirtualKeyCode::LAlt => Some(Key::LeftAlt), + VirtualKeyCode::LWin => Some(Key::LeftSuper), + VirtualKeyCode::RControl => Some(Key::RightCtrl), + VirtualKeyCode::RShift => Some(Key::RightShift), + VirtualKeyCode::RAlt => Some(Key::RightAlt), + VirtualKeyCode::RWin => Some(Key::RightSuper), + //VirtualKeyCode::Menu => Some(Key::Menu), // TODO: find out if there is a Menu key in winit + VirtualKeyCode::Key0 => Some(Key::Alpha0), + VirtualKeyCode::Key1 => Some(Key::Alpha1), + VirtualKeyCode::Key2 => Some(Key::Alpha2), + VirtualKeyCode::Key3 => Some(Key::Alpha3), + VirtualKeyCode::Key4 => Some(Key::Alpha4), + VirtualKeyCode::Key5 => Some(Key::Alpha5), + VirtualKeyCode::Key6 => Some(Key::Alpha6), + VirtualKeyCode::Key7 => Some(Key::Alpha7), + VirtualKeyCode::Key8 => Some(Key::Alpha8), + VirtualKeyCode::Key9 => Some(Key::Alpha9), + VirtualKeyCode::A => Some(Key::A), + VirtualKeyCode::B => Some(Key::B), + VirtualKeyCode::C => Some(Key::C), + VirtualKeyCode::D => Some(Key::D), + VirtualKeyCode::E => Some(Key::E), + VirtualKeyCode::F => Some(Key::F), + VirtualKeyCode::G => Some(Key::G), + VirtualKeyCode::H => Some(Key::H), + VirtualKeyCode::I => Some(Key::I), + VirtualKeyCode::J => Some(Key::J), + VirtualKeyCode::K => Some(Key::K), + VirtualKeyCode::L => Some(Key::L), + VirtualKeyCode::M => Some(Key::M), + VirtualKeyCode::N => Some(Key::N), + VirtualKeyCode::O => Some(Key::O), + VirtualKeyCode::P => Some(Key::P), + VirtualKeyCode::Q => Some(Key::Q), + VirtualKeyCode::R => Some(Key::R), + VirtualKeyCode::S => Some(Key::S), + VirtualKeyCode::T => Some(Key::T), + VirtualKeyCode::U => Some(Key::U), + VirtualKeyCode::V => Some(Key::V), + VirtualKeyCode::W => Some(Key::W), + VirtualKeyCode::X => Some(Key::X), + VirtualKeyCode::Y => Some(Key::Y), + VirtualKeyCode::Z => Some(Key::Z), + VirtualKeyCode::F1 => Some(Key::F1), + VirtualKeyCode::F2 => Some(Key::F2), + VirtualKeyCode::F3 => Some(Key::F3), + VirtualKeyCode::F4 => Some(Key::F4), + VirtualKeyCode::F5 => Some(Key::F5), + VirtualKeyCode::F6 => Some(Key::F6), + VirtualKeyCode::F7 => Some(Key::F7), + VirtualKeyCode::F8 => Some(Key::F8), + VirtualKeyCode::F9 => Some(Key::F9), + VirtualKeyCode::F10 => Some(Key::F10), + VirtualKeyCode::F11 => Some(Key::F11), + VirtualKeyCode::F12 => Some(Key::F12), + VirtualKeyCode::Apostrophe => Some(Key::Apostrophe), + VirtualKeyCode::Comma => Some(Key::Comma), + VirtualKeyCode::Minus => Some(Key::Minus), + VirtualKeyCode::Period => Some(Key::Period), + VirtualKeyCode::Slash => Some(Key::Slash), + VirtualKeyCode::Semicolon => Some(Key::Semicolon), + VirtualKeyCode::Equals => Some(Key::Equal), + VirtualKeyCode::LBracket => Some(Key::LeftBracket), + VirtualKeyCode::Backslash => Some(Key::Backslash), + VirtualKeyCode::RBracket => Some(Key::RightBracket), + VirtualKeyCode::Grave => Some(Key::GraveAccent), + VirtualKeyCode::Capital => Some(Key::CapsLock), + VirtualKeyCode::Scroll => Some(Key::ScrollLock), + VirtualKeyCode::Numlock => Some(Key::NumLock), + VirtualKeyCode::Snapshot => Some(Key::PrintScreen), + VirtualKeyCode::Pause => Some(Key::Pause), + VirtualKeyCode::Numpad0 => Some(Key::Keypad0), + VirtualKeyCode::Numpad1 => Some(Key::Keypad1), + VirtualKeyCode::Numpad2 => Some(Key::Keypad2), + VirtualKeyCode::Numpad3 => Some(Key::Keypad3), + VirtualKeyCode::Numpad4 => Some(Key::Keypad4), + VirtualKeyCode::Numpad5 => Some(Key::Keypad5), + VirtualKeyCode::Numpad6 => Some(Key::Keypad6), + VirtualKeyCode::Numpad7 => Some(Key::Keypad7), + VirtualKeyCode::Numpad8 => Some(Key::Keypad8), + VirtualKeyCode::Numpad9 => Some(Key::Keypad9), + VirtualKeyCode::NumpadDecimal => Some(Key::KeypadDecimal), + VirtualKeyCode::NumpadDivide => Some(Key::KeypadDivide), + VirtualKeyCode::NumpadMultiply => Some(Key::KeypadMultiply), + VirtualKeyCode::NumpadSubtract => Some(Key::KeypadSubtract), + VirtualKeyCode::NumpadAdd => Some(Key::KeypadAdd), + VirtualKeyCode::NumpadEnter => Some(Key::KeypadEnter), + VirtualKeyCode::NumpadEquals => Some(Key::KeypadEqual), + _ => None, + } +} + +fn to_imgui_mouse_button(button: winit::event::MouseButton) -> Option { + match button { + winit::event::MouseButton::Left | winit::event::MouseButton::Other(0) => { + Some(imgui::MouseButton::Left) + } + winit::event::MouseButton::Right | winit::event::MouseButton::Other(1) => { + Some(imgui::MouseButton::Right) + } + winit::event::MouseButton::Middle | winit::event::MouseButton::Other(2) => { + Some(imgui::MouseButton::Middle) + } + winit::event::MouseButton::Other(3) => Some(imgui::MouseButton::Extra1), + winit::event::MouseButton::Other(4) => Some(imgui::MouseButton::Extra2), + _ => None, + } +} From ce92bd6dd1402323bca7ce87418ce0a32ba4a865 Mon Sep 17 00:00:00 2001 From: Robin Date: Sat, 21 Jan 2023 21:16:12 +0100 Subject: [PATCH 39/42] Clippy fixes in imgui-winit-glow-renderer-viewports --- .../src/lib.rs | 85 +++++++++---------- 1 file changed, 38 insertions(+), 47 deletions(-) diff --git a/imgui-winit-glow-renderer-viewports/src/lib.rs b/imgui-winit-glow-renderer-viewports/src/lib.rs index 9ed5c9e..3a2c8fa 100644 --- a/imgui-winit-glow-renderer-viewports/src/lib.rs +++ b/imgui-winit-glow-renderer-viewports/src/lib.rs @@ -105,7 +105,7 @@ impl GlObjects { let program = unsafe { let vertex_shader = glow .create_shader(glow::VERTEX_SHADER) - .map_err(|e| RendererError::GlShaderCreationFailed(e))?; + .map_err(RendererError::GlShaderCreationFailed)?; glow.shader_source(vertex_shader, VERTEX_SHADER); glow.compile_shader(vertex_shader); assert!( @@ -115,7 +115,7 @@ impl GlObjects { let fragment_shader = glow .create_shader(glow::FRAGMENT_SHADER) - .map_err(|e| RendererError::GlShaderCreationFailed(e))?; + .map_err(RendererError::GlShaderCreationFailed)?; glow.shader_source(fragment_shader, FRAGMENT_SHADER); glow.compile_shader(fragment_shader); assert!( @@ -125,7 +125,7 @@ impl GlObjects { let program = glow .create_program() - .map_err(|e| RendererError::GlProgramCreationFailed(e))?; + .map_err(RendererError::GlProgramCreationFailed)?; glow.attach_shader(program, vertex_shader); glow.attach_shader(program, fragment_shader); glow.link_program(program); @@ -143,7 +143,7 @@ impl GlObjects { let font_texture = unsafe { let tex = glow .create_texture() - .map_err(|e| RendererError::GlTextureCreationFailed(e))?; + .map_err(RendererError::GlTextureCreationFailed)?; glow.bind_texture(glow::TEXTURE_2D, Some(tex)); glow.tex_parameter_i32( glow::TEXTURE_2D, @@ -182,17 +182,17 @@ impl GlObjects { let vbo = unsafe { glow.create_buffer() - .map_err(|e| RendererError::GlBufferCreationFailed(e))? + .map_err(RendererError::GlBufferCreationFailed)? }; let ibo = unsafe { glow.create_buffer() - .map_err(|e| RendererError::GlBufferCreationFailed(e))? + .map_err(RendererError::GlBufferCreationFailed)? }; let vao = unsafe { let vao = glow .create_vertex_array() - .map_err(|e| RendererError::GlVertexArrayCreationFailed(e))?; + .map_err(RendererError::GlVertexArrayCreationFailed)?; glow.bind_vertex_array(Some(vao)); glow.bind_buffer(glow::ARRAY_BUFFER, Some(vbo)); @@ -454,24 +454,22 @@ impl Renderer { } => { let (window, viewport) = if window_id == main_window.id() { (main_window, imgui.main_viewport_mut()) - } else { - 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) { - (wnd, viewport) + } else if let Some((id, wnd)) = + self.extra_windows.iter().find_map(|(id, (_, _, _, wnd))| { + if wnd.id() == window_id { + Some((*id, wnd)) } else { - return; + None } + }) + { + if let Some(viewport) = imgui.viewport_by_id_mut(id) { + (wnd, viewport) } else { return; } + } else { + return; }; match *event { @@ -675,7 +673,7 @@ impl Renderer { if self.last_cursor != cursor { main_window.set_cursor_icon(cursor); - for (_, (_, _, _, wnd)) in &self.extra_windows { + for (_, _, _, wnd) in self.extra_windows.values() { wnd.set_cursor_icon(cursor); } @@ -730,7 +728,7 @@ impl Renderer { let context = unsafe { glutin_config .display() - .create_context(&glutin_config, &context_attribs) + .create_context(glutin_config, &context_attribs) .map_err(|_| RendererError::WindowContextCreationFailed)? }; @@ -872,32 +870,25 @@ impl Renderer { ); for cmd in list.commands() { - match cmd { - imgui::DrawCmd::Elements { count, cmd_params } => { - 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; + if let imgui::DrawCmd::Elements { count, cmd_params } = cmd { + 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, - ); - } - _ => {} + 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, + ); } } } From b730a88d003ca843236a98822ca8f04381fe485f Mon Sep 17 00:00:00 2001 From: dbr Date: Mon, 30 Jan 2023 16:55:56 +1030 Subject: [PATCH 40/42] Rename viewport example Mostly so when running "cargo run --example" it is clearer --- .../examples/{basic.rs => viewports_basic.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename imgui-winit-glow-renderer-viewports/examples/{basic.rs => viewports_basic.rs} (100%) diff --git a/imgui-winit-glow-renderer-viewports/examples/basic.rs b/imgui-winit-glow-renderer-viewports/examples/viewports_basic.rs similarity index 100% rename from imgui-winit-glow-renderer-viewports/examples/basic.rs rename to imgui-winit-glow-renderer-viewports/examples/viewports_basic.rs From 6cd80834e5904587f3a6cae675bbe1ae6c963cd8 Mon Sep 17 00:00:00 2001 From: dbr Date: Mon, 30 Jan 2023 17:00:11 +1030 Subject: [PATCH 41/42] Missing 'mut' in unsafe{} comment --- imgui/src/context.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui/src/context.rs b/imgui/src/context.rs index 5cb7abb..67bb786 100644 --- a/imgui/src/context.rs +++ b/imgui/src/context.rs @@ -659,7 +659,7 @@ impl Context { /// Returns an iterator containing every [`Viewport`](crate::Viewport) that currently exists. pub fn viewports_mut(&mut self) -> impl Iterator { let slice = self.platform_io_mut().viewports.as_slice(); - // safe because &self ensures exclusive ownership + // safe because &mut self ensures exclusive ownership unsafe { slice.iter().map(|ptr| &mut **ptr) } } From 29978d3a31be7236a32ac25ce69bd2fb3feb81ed Mon Sep 17 00:00:00 2001 From: dbr Date: Mon, 30 Jan 2023 17:03:56 +1030 Subject: [PATCH 42/42] Fix clippy lint in example --- imgui-examples/examples/tables_api.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui-examples/examples/tables_api.rs b/imgui-examples/examples/tables_api.rs index 47a1d7d..1263617 100644 --- a/imgui-examples/examples/tables_api.rs +++ b/imgui-examples/examples/tables_api.rs @@ -190,7 +190,7 @@ struct HumanData { } impl HumanData { - pub fn sort_humans(humans: &mut Vec, specs: Specs<'_>) { + pub fn sort_humans(humans: &mut [Self], specs: Specs<'_>) { let spec = specs.iter().next().unwrap(); if let Some(kind) = spec.sort_direction() { match kind {