diff --git a/Cargo.toml b/Cargo.toml index f0438d1..6676ec0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,11 +2,6 @@ members = [ "imgui", "imgui-sys", - "imgui-glium-renderer", - "imgui-glow-renderer", - "imgui-sdl2-support", - "imgui-winit-support", - "imgui-winit-glow-renderer-viewports", "imgui-examples", "xtask", ] diff --git a/imgui-examples/Cargo.toml b/imgui-examples/Cargo.toml index 6accc2e..061b513 100644 --- a/imgui-examples/Cargo.toml +++ b/imgui-examples/Cargo.toml @@ -13,13 +13,8 @@ copypasta = "0.8" glium = { version = "0.34.0", 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" } -# Pin indirect dependency scoped-tls to 1.0.0 -# as 1.0.1 bumped MSRV to 1.59 -# Used only in -# imgui-examples -> glium -> glutin -> wayland-client -> scoped-tls -# so not worth bumping MSRV for this basically to keep CI happy -# FIXME: Remove this for imgui-rs v0.10 and bump MSRV -scoped-tls = "=1.0.0" +[dependencies] +imgui-glium-renderer = "0.12.0" +# imgui-glium-renderer = { path = "../imgui-glium-renderer" } +# imgui-winit-support = { path = "../imgui-winit-support" } diff --git a/imgui-glium-renderer/Cargo.toml b/imgui-glium-renderer/Cargo.toml deleted file mode 100644 index df7fd01..0000000 --- a/imgui-glium-renderer/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "imgui-glium-renderer" -version = "0.12.0" -edition = "2021" -description = "Glium renderer for the imgui crate" -homepage = "https://github.com/imgui-rs/imgui-rs" -repository = "https://github.com/imgui-rs/imgui-rs" -documentation = "https://docs.rs/imgui-glium-renderer" -license = "MIT OR Apache-2.0" -categories = ["gui", "rendering"] - -[dependencies] -glium = { version = "0.34.0", default-features = false } -imgui = { version = "0.12.0", path = "../imgui" } - -[dev-dependencies] -glium = { version = "0.34.0", default-features = false, features = ["glutin_backend"] } -imgui-winit-support = {path = "../imgui-winit-support"} -glutin = "0.31" -glutin-winit = "0.4.2" -winit = { version = "0.29.3", features = ["rwh_05"] } -raw-window-handle = "0.5.0" diff --git a/imgui-glium-renderer/LICENSE-APACHE b/imgui-glium-renderer/LICENSE-APACHE deleted file mode 100644 index 3b7a7f9..0000000 --- a/imgui-glium-renderer/LICENSE-APACHE +++ /dev/null @@ -1,202 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2021 the imgui-rs developers - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - diff --git a/imgui-glium-renderer/LICENSE-MIT b/imgui-glium-renderer/LICENSE-MIT deleted file mode 100644 index 230b8c4..0000000 --- a/imgui-glium-renderer/LICENSE-MIT +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2021 The imgui-rs Developers - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/imgui-glium-renderer/examples/glium_01_basic.rs b/imgui-glium-renderer/examples/glium_01_basic.rs deleted file mode 100644 index b57c419..0000000 --- a/imgui-glium-renderer/examples/glium_01_basic.rs +++ /dev/null @@ -1,149 +0,0 @@ -use std::num::NonZeroU32; - -use glium::Surface; -use glutin::{ - config::ConfigTemplateBuilder, - context::{ContextAttributesBuilder, NotCurrentGlContext}, - display::{GetGlDisplay, GlDisplay}, - surface::{SurfaceAttributesBuilder, WindowSurface}, -}; -use imgui_winit_support::winit::{dpi::LogicalSize, event_loop::EventLoop, window::WindowBuilder}; -use raw_window_handle::HasRawWindowHandle; -use winit::{ - event::{Event, WindowEvent}, - window::Window, -}; - -const TITLE: &str = "Hello, imgui-rs!"; - -fn main() { - // Common setup for creating a winit window and imgui context, not specifc - // to this renderer at all except that glutin is used to create the window - // since it will give us access to a GL context - let (event_loop, window, display) = create_window(); - let (mut winit_platform, mut imgui_context) = imgui_init(&window); - - // Create renderer from this crate - let mut renderer = imgui_glium_renderer::Renderer::init(&mut imgui_context, &display) - .expect("Failed to initialize renderer"); - - // Timer for FPS calculation - let mut last_frame = std::time::Instant::now(); - - // Standard winit event loop - event_loop - .run(move |event, window_target| match event { - Event::NewEvents(_) => { - let now = std::time::Instant::now(); - imgui_context.io_mut().update_delta_time(now - last_frame); - last_frame = now; - } - Event::AboutToWait => { - winit_platform - .prepare_frame(imgui_context.io_mut(), &window) - .expect("Failed to prepare frame"); - window.request_redraw(); - } - Event::WindowEvent { - event: WindowEvent::RedrawRequested, - .. - } => { - // Create frame for the all important `&imgui::Ui` - let ui = imgui_context.frame(); - - // Draw our example content - ui.show_demo_window(&mut true); - - // Setup for drawing - let mut target = display.draw(); - - // Renderer doesn't automatically clear window - target.clear_color_srgb(1.0, 1.0, 1.0, 1.0); - - // Perform rendering - winit_platform.prepare_render(ui, &window); - let draw_data = imgui_context.render(); - renderer - .render(&mut target, draw_data) - .expect("Rendering failed"); - target.finish().expect("Failed to swap buffers"); - } - Event::WindowEvent { - event: WindowEvent::CloseRequested, - .. - } => window_target.exit(), - winit::event::Event::WindowEvent { - event: winit::event::WindowEvent::Resized(new_size), - .. - } => { - if new_size.width > 0 && new_size.height > 0 { - display.resize((new_size.width, new_size.height)); - } - winit_platform.handle_event(imgui_context.io_mut(), &window, &event); - } - event => { - winit_platform.handle_event(imgui_context.io_mut(), &window, &event); - } - }) - .expect("EventLoop error"); -} - -fn create_window() -> (EventLoop<()>, Window, glium::Display) { - let event_loop = EventLoop::new().expect("Failed to create EventLoop"); - - let window_builder = WindowBuilder::new() - .with_title(TITLE) - .with_inner_size(LogicalSize::new(1024, 768)); - - let (window, cfg) = glutin_winit::DisplayBuilder::new() - .with_window_builder(Some(window_builder)) - .build(&event_loop, ConfigTemplateBuilder::new(), |mut configs| { - configs.next().unwrap() - }) - .expect("Failed to create OpenGL window"); - let window = window.unwrap(); - - let context_attribs = ContextAttributesBuilder::new().build(Some(window.raw_window_handle())); - let context = unsafe { - cfg.display() - .create_context(&cfg, &context_attribs) - .expect("Failed to create OpenGL context") - }; - - let surface_attribs = SurfaceAttributesBuilder::::new().build( - window.raw_window_handle(), - NonZeroU32::new(1024).unwrap(), - NonZeroU32::new(768).unwrap(), - ); - let surface = unsafe { - cfg.display() - .create_window_surface(&cfg, &surface_attribs) - .expect("Failed to create OpenGL surface") - }; - - let context = context - .make_current(&surface) - .expect("Failed to make OpenGL context current"); - - let display = glium::Display::from_context_surface(context, surface) - .expect("Failed to create glium Display"); - - (event_loop, window, display) -} - -fn imgui_init(window: &Window) -> (imgui_winit_support::WinitPlatform, imgui::Context) { - let mut imgui_context = imgui::Context::create(); - imgui_context.set_ini_filename(None); - - let mut winit_platform = imgui_winit_support::WinitPlatform::init(&mut imgui_context); - - let dpi_mode = imgui_winit_support::HiDpiMode::Default; - - winit_platform.attach_window(imgui_context.io_mut(), window, dpi_mode); - - imgui_context - .fonts() - .add_font(&[imgui::FontSource::DefaultFontData { config: None }]); - - (winit_platform, imgui_context) -} diff --git a/imgui-glium-renderer/src/lib.rs b/imgui-glium-renderer/src/lib.rs deleted file mode 100644 index 82ea24c..0000000 --- a/imgui-glium-renderer/src/lib.rs +++ /dev/null @@ -1,349 +0,0 @@ -pub extern crate glium; -pub extern crate imgui; - -use glium::backend::{Context, Facade}; -use glium::index::{self, PrimitiveType}; -use glium::program::ProgramChooserCreationError; -use glium::texture::{ClientFormat, MipmapsOption, RawImage2d, TextureCreationError}; -use glium::uniforms::{ - MagnifySamplerFilter, MinifySamplerFilter, Sampler, SamplerBehavior, SamplerWrapFunction, -}; -use glium::{ - program, uniform, vertex, Blend, BlendingFunction, DrawError, DrawParameters, IndexBuffer, - LinearBlendingFactor, Program, Rect, Surface, Texture2d, VertexBuffer, -}; -use imgui::internal::RawWrapper; -use imgui::{BackendFlags, DrawCmd, DrawCmdParams, DrawData, TextureId, Textures}; -use std::borrow::Cow; -use std::error::Error; -use std::fmt; -use std::rc::Rc; -use std::usize; - -#[derive(Clone, Debug)] -pub enum RendererError { - Vertex(vertex::BufferCreationError), - Index(index::BufferCreationError), - Program(ProgramChooserCreationError), - Texture(TextureCreationError), - Draw(DrawError), - BadTexture(TextureId), -} - -impl Error for RendererError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - use self::RendererError::*; - match *self { - Vertex(ref e) => Some(e), - Index(ref e) => Some(e), - Program(ref e) => Some(e), - Texture(ref e) => Some(e), - Draw(ref e) => Some(e), - BadTexture(_) => None, - } - } -} - -impl fmt::Display for RendererError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use self::RendererError::*; - match *self { - Vertex(_) => write!(f, "Vertex buffer creation failed"), - Index(_) => write!(f, "Index buffer creation failed"), - Program(ref e) => write!(f, "Program creation failed: {}", e), - Texture(_) => write!(f, "Texture creation failed"), - Draw(ref e) => write!(f, "Drawing failed: {}", e), - BadTexture(ref t) => write!(f, "Bad texture ID: {}", t.id()), - } - } -} - -impl From for RendererError { - fn from(e: vertex::BufferCreationError) -> RendererError { - RendererError::Vertex(e) - } -} - -impl From for RendererError { - fn from(e: index::BufferCreationError) -> RendererError { - RendererError::Index(e) - } -} - -impl From for RendererError { - fn from(e: ProgramChooserCreationError) -> RendererError { - RendererError::Program(e) - } -} - -impl From for RendererError { - fn from(e: TextureCreationError) -> RendererError { - RendererError::Texture(e) - } -} - -impl From for RendererError { - fn from(e: DrawError) -> RendererError { - RendererError::Draw(e) - } -} - -pub struct Texture { - pub texture: Rc, - pub sampler: SamplerBehavior, -} - -pub struct Renderer { - ctx: Rc, - program: Program, - font_texture: Texture, - textures: Textures, -} - -#[repr(C)] -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct GliumDrawVert { - pub pos: [f32; 2], - pub uv: [f32; 2], - pub col: [u8; 4], -} - -// manual impl to avoid an allocation, and to reduce macro wonkiness. -impl glium::vertex::Vertex for GliumDrawVert { - #[inline] - fn build_bindings() -> glium::vertex::VertexFormat { - use std::borrow::Cow::*; - &[ - ( - Borrowed("pos"), - 0, - -1, - glium::vertex::AttributeType::F32F32, - false, - ), - ( - Borrowed("uv"), - 8, - -1, - glium::vertex::AttributeType::F32F32, - false, - ), - ( - Borrowed("col"), - 16, - -1, - glium::vertex::AttributeType::U8U8U8U8, - false, - ), - ] - } -} - -impl Renderer { - pub fn init( - ctx: &mut imgui::Context, - facade: &F, - ) -> Result { - let program = compile_default_program(facade)?; - let font_texture = upload_font_texture(ctx.fonts(), facade.get_context())?; - ctx.set_renderer_name(Some(format!( - "imgui-glium-renderer {}", - env!("CARGO_PKG_VERSION") - ))); - ctx.io_mut() - .backend_flags - .insert(BackendFlags::RENDERER_HAS_VTX_OFFSET); - Ok(Renderer { - ctx: Rc::clone(facade.get_context()), - program, - font_texture, - textures: Textures::new(), - }) - } - pub fn reload_font_texture(&mut self, ctx: &mut imgui::Context) -> Result<(), RendererError> { - self.font_texture = upload_font_texture(ctx.fonts(), &self.ctx)?; - Ok(()) - } - pub fn textures(&mut self) -> &mut Textures { - &mut self.textures - } - fn lookup_texture(&self, texture_id: TextureId) -> Result<&Texture, RendererError> { - if texture_id.id() == usize::MAX { - Ok(&self.font_texture) - } else if let Some(texture) = self.textures.get(texture_id) { - Ok(texture) - } else { - Err(RendererError::BadTexture(texture_id)) - } - } - pub fn render( - &mut self, - target: &mut T, - draw_data: &DrawData, - ) -> Result<(), RendererError> { - let fb_width = draw_data.display_size[0] * draw_data.framebuffer_scale[0]; - let fb_height = draw_data.display_size[1] * draw_data.framebuffer_scale[1]; - if !(fb_width > 0.0 && fb_height > 0.0) { - return Ok(()); - } - let _ = self.ctx.insert_debug_marker("imgui-rs: starting rendering"); - 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 clip_off = draw_data.display_pos; - let clip_scale = draw_data.framebuffer_scale; - for draw_list in draw_data.draw_lists() { - let vtx_buffer = VertexBuffer::immutable(&self.ctx, unsafe { - draw_list.transmute_vtx_buffer::() - })?; - let idx_buffer = IndexBuffer::immutable( - &self.ctx, - PrimitiveType::TrianglesList, - draw_list.idx_buffer(), - )?; - for cmd in draw_list.commands() { - match cmd { - DrawCmd::Elements { - count, - cmd_params: - DrawCmdParams { - clip_rect, - texture_id, - vtx_offset, - idx_offset, - .. - }, - } => { - let clip_rect = [ - (clip_rect[0] - clip_off[0]) * clip_scale[0], - (clip_rect[1] - clip_off[1]) * clip_scale[1], - (clip_rect[2] - clip_off[0]) * clip_scale[0], - (clip_rect[3] - clip_off[1]) * clip_scale[1], - ]; - - if clip_rect[0] < fb_width - && clip_rect[1] < fb_height - && clip_rect[2] >= 0.0 - && clip_rect[3] >= 0.0 - { - let texture = self.lookup_texture(texture_id)?; - - target.draw( - vtx_buffer - .slice(vtx_offset..) - .expect("Invalid vertex buffer range"), - idx_buffer - .slice(idx_offset..(idx_offset + count)) - .expect("Invalid index buffer range"), - &self.program, - &uniform! { - matrix: matrix, - tex: Sampler(texture.texture.as_ref(), texture.sampler) - }, - &DrawParameters { - blend: Blend { - alpha: BlendingFunction::Addition { - source: LinearBlendingFactor::One, - destination: LinearBlendingFactor::OneMinusSourceAlpha, - }, - ..Blend::alpha_blending() - }, - scissor: Some(Rect { - left: f32::max(0.0, clip_rect[0]).floor() as u32, - bottom: f32::max(0.0, fb_height - clip_rect[3]).floor() - as u32, - width: (clip_rect[2] - clip_rect[0]).abs().ceil() as u32, - height: (clip_rect[3] - clip_rect[1]).abs().ceil() as u32, - }), - ..DrawParameters::default() - }, - )?; - } - } - DrawCmd::ResetRenderState => (), // TODO - DrawCmd::RawCallback { callback, raw_cmd } => unsafe { - callback(draw_list.raw(), raw_cmd) - }, - } - } - } - let _ = self.ctx.insert_debug_marker("imgui-rs: rendering finished"); - Ok(()) - } -} - -fn upload_font_texture( - fonts: &mut imgui::FontAtlas, - ctx: &Rc, -) -> Result { - let texture = fonts.build_rgba32_texture(); - let data = RawImage2d { - data: Cow::Borrowed(texture.data), - width: texture.width, - height: texture.height, - format: ClientFormat::U8U8U8U8, - }; - let font_texture = Texture2d::with_mipmaps(ctx, data, MipmapsOption::NoMipmap)?; - fonts.tex_id = TextureId::from(usize::MAX); - Ok(Texture { - texture: Rc::new(font_texture), - sampler: SamplerBehavior { - minify_filter: MinifySamplerFilter::Linear, - magnify_filter: MagnifySamplerFilter::Linear, - wrap_function: ( - SamplerWrapFunction::BorderClamp, - SamplerWrapFunction::BorderClamp, - SamplerWrapFunction::BorderClamp, - ), - ..Default::default() - }, - }) -} - -fn compile_default_program(facade: &F) -> Result { - program!( - facade, - 400 => { - vertex: include_str!("shader/glsl_400.vert"), - fragment: include_str!("shader/glsl_400.frag"), - outputs_srgb: true, - }, - 150 => { - vertex: include_str!("shader/glsl_150.vert"), - fragment: include_str!("shader/glsl_150.frag"), - outputs_srgb: true, - }, - 130 => { - vertex: include_str!("shader/glsl_130.vert"), - fragment: include_str!("shader/glsl_130.frag"), - outputs_srgb: true, - }, - 110 => { - vertex: include_str!("shader/glsl_110.vert"), - fragment: include_str!("shader/glsl_110.frag"), - outputs_srgb: true, - }, - 300 es => { - vertex: include_str!("shader/glsles_300.vert"), - fragment: include_str!("shader/glsles_300.frag"), - outputs_srgb: true, - }, - 100 es => { - vertex: include_str!("shader/glsles_100.vert"), - fragment: include_str!("shader/glsles_100.frag"), - outputs_srgb: true, - }, - ) -} diff --git a/imgui-glium-renderer/src/shader/glsl_110.frag b/imgui-glium-renderer/src/shader/glsl_110.frag deleted file mode 100644 index d45b190..0000000 --- a/imgui-glium-renderer/src/shader/glsl_110.frag +++ /dev/null @@ -1,13 +0,0 @@ -#version 110 - -uniform sampler2D tex; - -varying vec2 f_uv; -varying vec4 f_color; - -// Built-in: -// vec4 gl_FragColor - -void main() { - gl_FragColor = f_color * texture2D(tex, f_uv.st); -} diff --git a/imgui-glium-renderer/src/shader/glsl_110.vert b/imgui-glium-renderer/src/shader/glsl_110.vert deleted file mode 100644 index 6c50194..0000000 --- a/imgui-glium-renderer/src/shader/glsl_110.vert +++ /dev/null @@ -1,19 +0,0 @@ -#version 110 - -uniform mat4 matrix; - -attribute vec2 pos; -attribute vec2 uv; -attribute vec4 col; - -varying vec2 f_uv; -varying vec4 f_color; - -// Built-in: -// vec4 gl_Position - -void main() { - f_uv = uv; - f_color = col / 255.0; - gl_Position = matrix * vec4(pos.xy, 0, 1); -} diff --git a/imgui-glium-renderer/src/shader/glsl_130.frag b/imgui-glium-renderer/src/shader/glsl_130.frag deleted file mode 100644 index c2e20c5..0000000 --- a/imgui-glium-renderer/src/shader/glsl_130.frag +++ /dev/null @@ -1,12 +0,0 @@ -#version 130 - -uniform sampler2D tex; - -in vec2 f_uv; -in vec4 f_color; - -out vec4 out_color; - -void main() { - out_color = f_color * texture(tex, f_uv.st); -} diff --git a/imgui-glium-renderer/src/shader/glsl_130.vert b/imgui-glium-renderer/src/shader/glsl_130.vert deleted file mode 100644 index 4b1da7b..0000000 --- a/imgui-glium-renderer/src/shader/glsl_130.vert +++ /dev/null @@ -1,19 +0,0 @@ -#version 130 - -uniform mat4 matrix; - -in vec2 pos; -in vec2 uv; -in vec4 col; - -out vec2 f_uv; -out vec4 f_color; - -// Built-in: -// vec4 gl_Position - -void main() { - f_uv = uv; - f_color = col / 255.0; - gl_Position = matrix * vec4(pos.xy, 0, 1); -} diff --git a/imgui-glium-renderer/src/shader/glsl_150.frag b/imgui-glium-renderer/src/shader/glsl_150.frag deleted file mode 100644 index 26e56b5..0000000 --- a/imgui-glium-renderer/src/shader/glsl_150.frag +++ /dev/null @@ -1,12 +0,0 @@ -#version 150 - -uniform sampler2D tex; - -in vec2 f_uv; -in vec4 f_color; - -out vec4 out_color; - -void main() { - out_color = f_color * texture(tex, f_uv.st); -} diff --git a/imgui-glium-renderer/src/shader/glsl_150.vert b/imgui-glium-renderer/src/shader/glsl_150.vert deleted file mode 100644 index 039d50b..0000000 --- a/imgui-glium-renderer/src/shader/glsl_150.vert +++ /dev/null @@ -1,19 +0,0 @@ -#version 150 - -uniform mat4 matrix; - -in vec2 pos; -in vec2 uv; -in vec4 col; - -out vec2 f_uv; -out vec4 f_color; - -// Built-in: -// vec4 gl_Position - -void main() { - f_uv = uv; - f_color = col / 255.0; - gl_Position = matrix * vec4(pos.xy, 0, 1); -} diff --git a/imgui-glium-renderer/src/shader/glsl_400.frag b/imgui-glium-renderer/src/shader/glsl_400.frag deleted file mode 100644 index 8b450ee..0000000 --- a/imgui-glium-renderer/src/shader/glsl_400.frag +++ /dev/null @@ -1,12 +0,0 @@ -#version 400 - -uniform sampler2D tex; - -in vec2 f_uv; -in vec4 f_color; - -out vec4 out_color; - -void main() { - out_color = f_color * texture(tex, f_uv.st); -} diff --git a/imgui-glium-renderer/src/shader/glsl_400.vert b/imgui-glium-renderer/src/shader/glsl_400.vert deleted file mode 100644 index 1ba880e..0000000 --- a/imgui-glium-renderer/src/shader/glsl_400.vert +++ /dev/null @@ -1,19 +0,0 @@ -#version 400 - -uniform mat4 matrix; - -in vec2 pos; -in vec2 uv; -in vec4 col; - -out vec2 f_uv; -out vec4 f_color; - -// Built-in: -// vec4 gl_Position - -void main() { - f_uv = uv; - f_color = col / 255.0; - gl_Position = matrix * vec4(pos.xy, 0, 1); -} diff --git a/imgui-glium-renderer/src/shader/glsles_100.frag b/imgui-glium-renderer/src/shader/glsles_100.frag deleted file mode 100644 index dd01b09..0000000 --- a/imgui-glium-renderer/src/shader/glsles_100.frag +++ /dev/null @@ -1,13 +0,0 @@ -#version 100 - -uniform sampler2D tex; - -varying mediump vec2 f_uv; -varying lowp vec4 f_color; - -// Built-in: -// vec4 gl_FragColor - -void main() { - gl_FragColor = f_color * texture2D(tex, f_uv.st); -} diff --git a/imgui-glium-renderer/src/shader/glsles_100.vert b/imgui-glium-renderer/src/shader/glsles_100.vert deleted file mode 100644 index 39cc5cb..0000000 --- a/imgui-glium-renderer/src/shader/glsles_100.vert +++ /dev/null @@ -1,19 +0,0 @@ -#version 100 - -uniform mat4 matrix; - -attribute mediump vec2 pos; -attribute mediump vec2 uv; -attribute lowp vec4 col; - -varying mediump vec2 f_uv; -varying lowp vec4 f_color; - -// Built-in: -// vec4 gl_Position - -void main() { - f_uv = uv; - f_color = col / 255.0; - gl_Position = matrix * vec4(pos.xy, 0, 1); -} diff --git a/imgui-glium-renderer/src/shader/glsles_300.frag b/imgui-glium-renderer/src/shader/glsles_300.frag deleted file mode 100644 index bda0f3c..0000000 --- a/imgui-glium-renderer/src/shader/glsles_300.frag +++ /dev/null @@ -1,12 +0,0 @@ -#version 300 es - -uniform sampler2D tex; - -in mediump vec2 f_uv; -in lowp vec4 f_color; - -out lowp vec4 out_color; - -void main() { - out_color = f_color * texture(tex, f_uv.st); -} diff --git a/imgui-glium-renderer/src/shader/glsles_300.vert b/imgui-glium-renderer/src/shader/glsles_300.vert deleted file mode 100644 index 019efbf..0000000 --- a/imgui-glium-renderer/src/shader/glsles_300.vert +++ /dev/null @@ -1,19 +0,0 @@ -#version 300 es - -uniform mat4 matrix; - -in mediump vec2 pos; -in mediump vec2 uv; -in lowp vec4 col; - -out mediump vec2 f_uv; -out lowp vec4 f_color; - -// Built-in: -// vec4 gl_Position - -void main() { - f_uv = uv; - f_color = col / 255.0; - gl_Position = matrix * vec4(pos.xy, 0, 1); -} diff --git a/imgui-glow-renderer/Cargo.toml b/imgui-glow-renderer/Cargo.toml deleted file mode 100644 index 175963e..0000000 --- a/imgui-glow-renderer/Cargo.toml +++ /dev/null @@ -1,55 +0,0 @@ -[package] -name = "imgui-glow-renderer" -version = "0.12.0" -edition = "2021" -description = "glow renderer for the imgui crate" -homepage = "https://github.com/imgui-rs/imgui-rs" -repository = "https://github.com/imgui-rs/imgui-rs" -license = "MIT OR Apache-2.0" -categories = ["gui", "rendering"] - -[dependencies] -imgui = { version = "0.12.0", path = "../imgui" } -glow = "0.13.1" -memoffset = "0.9" - -[dev-dependencies] -glutin = "0.31.1" -glutin-winit = "0.4.2" -imgui-winit-support = { version = "0.12.0", path = "../imgui-winit-support" } -image = "0.23" -raw-window-handle = "0.5.0" -winit = { version = "0.29.3", features = ["rwh_05"] } - -[features] -# Features here are used to opt-out of compiling code that depends on certain -# OpenGL features. If the features are enabled, the renderer will check that the -# feature is supported before attempting to use it. Only opt-out of any of these -# if you are certain you will only target platforms that lack the corresponding -# feature. -default = [ - "gl_extensions_support", - "debug_message_insert_support", - "bind_vertex_array_support", - "vertex_offset_support", - "clip_origin_support", - "bind_sampler_support", - "polygon_mode_support", - "primitive_restart_support", -] -# Enable checking for OpenGL extensions -gl_extensions_support = [] -# Support for `gl.debug_message_insert` -debug_message_insert_support = [] -# Support for `glBindVertexArray` -bind_vertex_array_support = [] -# Support for `glDrawElementsBaseVertex` -vertex_offset_support = [] -# Support for `GL_CLIP_ORIGIN` -clip_origin_support = [] -# Support for `glBindSampler` -bind_sampler_support = [] -# Support for `glPolygonMode` -polygon_mode_support = [] -# Support for `GL_PRIMITIVE_RESTART` -primitive_restart_support = [] diff --git a/imgui-glow-renderer/LICENSE-APACHE b/imgui-glow-renderer/LICENSE-APACHE deleted file mode 100644 index 3b7a7f9..0000000 --- a/imgui-glow-renderer/LICENSE-APACHE +++ /dev/null @@ -1,202 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2021 the imgui-rs developers - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - diff --git a/imgui-glow-renderer/LICENSE-MIT b/imgui-glow-renderer/LICENSE-MIT deleted file mode 100644 index 230b8c4..0000000 --- a/imgui-glow-renderer/LICENSE-MIT +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2021 The imgui-rs Developers - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/imgui-glow-renderer/examples/glow_01_basic.rs b/imgui-glow-renderer/examples/glow_01_basic.rs deleted file mode 100644 index 32b30ff..0000000 --- a/imgui-glow-renderer/examples/glow_01_basic.rs +++ /dev/null @@ -1,178 +0,0 @@ -//! A basic self-contained example to get you from zero-to-demo-window as fast -//! as possible. - -use std::{num::NonZeroU32, time::Instant}; - -use glow::HasContext; -use glutin::{ - config::ConfigTemplateBuilder, - context::{ContextAttributesBuilder, NotCurrentGlContext, PossiblyCurrentContext}, - display::{GetGlDisplay, GlDisplay}, - surface::{GlSurface, Surface, SurfaceAttributesBuilder, WindowSurface}, -}; -use imgui_winit_support::{ - winit::{ - dpi::LogicalSize, - event_loop::EventLoop, - window::{Window, WindowBuilder}, - }, - WinitPlatform, -}; -use raw_window_handle::HasRawWindowHandle; - -const TITLE: &str = "Hello, imgui-rs!"; - -fn main() { - // Common setup for creating a winit window and imgui context, not specifc - // to this renderer at all except that glutin is used to create the window - // since it will give us access to a GL context - let (event_loop, window, surface, context) = create_window(); - let (mut winit_platform, mut imgui_context) = imgui_init(&window); - - // OpenGL context from glow - let gl = glow_context(&context); - - // OpenGL renderer from this crate - let mut ig_renderer = imgui_glow_renderer::AutoRenderer::initialize(gl, &mut imgui_context) - .expect("failed to create renderer"); - - let mut last_frame = Instant::now(); - - // Standard winit event loop - event_loop - .run(move |event, window_target| { - match event { - winit::event::Event::NewEvents(_) => { - let now = Instant::now(); - imgui_context - .io_mut() - .update_delta_time(now.duration_since(last_frame)); - last_frame = now; - } - winit::event::Event::AboutToWait => { - winit_platform - .prepare_frame(imgui_context.io_mut(), &window) - .unwrap(); - window.request_redraw(); - } - winit::event::Event::WindowEvent { - event: winit::event::WindowEvent::RedrawRequested, - .. - } => { - // The renderer assumes you'll be clearing the buffer yourself - unsafe { ig_renderer.gl_context().clear(glow::COLOR_BUFFER_BIT) }; - - let ui = imgui_context.frame(); - ui.show_demo_window(&mut true); - - winit_platform.prepare_render(ui, &window); - let draw_data = imgui_context.render(); - - // This is the only extra render step to add - ig_renderer - .render(draw_data) - .expect("error rendering imgui"); - - surface - .swap_buffers(&context) - .expect("Failed to swap buffers"); - } - winit::event::Event::WindowEvent { - event: winit::event::WindowEvent::CloseRequested, - .. - } => { - window_target.exit(); - } - winit::event::Event::WindowEvent { - event: winit::event::WindowEvent::Resized(new_size), - .. - } => { - if new_size.width > 0 && new_size.height > 0 { - surface.resize( - &context, - NonZeroU32::new(new_size.width).unwrap(), - NonZeroU32::new(new_size.height).unwrap(), - ); - } - winit_platform.handle_event(imgui_context.io_mut(), &window, &event); - } - event => { - winit_platform.handle_event(imgui_context.io_mut(), &window, &event); - } - } - }) - .expect("EventLoop error"); -} - -fn create_window() -> ( - EventLoop<()>, - Window, - Surface, - PossiblyCurrentContext, -) { - let event_loop = EventLoop::new().unwrap(); - - let window_builder = WindowBuilder::new() - .with_title(TITLE) - .with_inner_size(LogicalSize::new(1024, 768)); - let (window, cfg) = glutin_winit::DisplayBuilder::new() - .with_window_builder(Some(window_builder)) - .build(&event_loop, ConfigTemplateBuilder::new(), |mut configs| { - configs.next().unwrap() - }) - .expect("Failed to create OpenGL window"); - - let window = window.unwrap(); - - let context_attribs = ContextAttributesBuilder::new().build(Some(window.raw_window_handle())); - let context = unsafe { - cfg.display() - .create_context(&cfg, &context_attribs) - .expect("Failed to create OpenGL context") - }; - - let surface_attribs = SurfaceAttributesBuilder::::new() - .with_srgb(Some(true)) - .build( - window.raw_window_handle(), - NonZeroU32::new(1024).unwrap(), - NonZeroU32::new(768).unwrap(), - ); - let surface = unsafe { - cfg.display() - .create_window_surface(&cfg, &surface_attribs) - .expect("Failed to create OpenGL surface") - }; - - let context = context - .make_current(&surface) - .expect("Failed to make OpenGL context current"); - - (event_loop, window, surface, context) -} - -fn glow_context(context: &PossiblyCurrentContext) -> glow::Context { - unsafe { - glow::Context::from_loader_function_cstr(|s| context.display().get_proc_address(s).cast()) - } -} - -fn imgui_init(window: &Window) -> (WinitPlatform, imgui::Context) { - let mut imgui_context = imgui::Context::create(); - imgui_context.set_ini_filename(None); - - let mut winit_platform = WinitPlatform::init(&mut imgui_context); - winit_platform.attach_window( - imgui_context.io_mut(), - window, - imgui_winit_support::HiDpiMode::Rounded, - ); - - imgui_context - .fonts() - .add_font(&[imgui::FontSource::DefaultFontData { config: None }]); - - imgui_context.io_mut().font_global_scale = (1.0 / winit_platform.hidpi_factor()) as f32; - - (winit_platform, imgui_context) -} diff --git a/imgui-glow-renderer/examples/glow_02_triangle.rs b/imgui-glow-renderer/examples/glow_02_triangle.rs deleted file mode 100644 index 09e984b..0000000 --- a/imgui-glow-renderer/examples/glow_02_triangle.rs +++ /dev/null @@ -1,89 +0,0 @@ -//! A basic example showing imgui rendering on top of a simple custom scene. - -use std::{num::NonZeroU32, time::Instant}; - -mod utils; - -use glutin::surface::GlSurface; -use utils::Triangler; - -fn main() { - let (event_loop, window, surface, context) = utils::create_window("Hello, triangle!", None); - let (mut winit_platform, mut imgui_context) = utils::imgui_init(&window); - let gl = utils::glow_context(&context); - - let mut ig_renderer = imgui_glow_renderer::AutoRenderer::initialize(gl, &mut imgui_context) - .expect("failed to create renderer"); - let tri_renderer = Triangler::new(ig_renderer.gl_context(), "#version 330"); - - let mut last_frame = Instant::now(); - event_loop - .run(move |event, window_target| { - match event { - winit::event::Event::NewEvents(_) => { - let now = Instant::now(); - imgui_context - .io_mut() - .update_delta_time(now.duration_since(last_frame)); - last_frame = now; - } - winit::event::Event::AboutToWait => { - winit_platform - .prepare_frame(imgui_context.io_mut(), &window) - .unwrap(); - - window.request_redraw(); - } - winit::event::Event::WindowEvent { - event: winit::event::WindowEvent::RedrawRequested, - .. - } => { - // Render your custom scene, note we need to borrow the OpenGL - // context from the `AutoRenderer`, which takes ownership of it. - tri_renderer.render(ig_renderer.gl_context()); - - let ui = imgui_context.frame(); - ui.show_demo_window(&mut true); - - winit_platform.prepare_render(ui, &window); - let draw_data = imgui_context.render(); - - // Render imgui on top of it - ig_renderer - .render(draw_data) - .expect("error rendering imgui"); - - surface - .swap_buffers(&context) - .expect("Failed to swap buffers"); - } - winit::event::Event::WindowEvent { - event: winit::event::WindowEvent::CloseRequested, - .. - } => { - window_target.exit(); - } - winit::event::Event::WindowEvent { - event: winit::event::WindowEvent::Resized(new_size), - .. - } => { - if new_size.width > 0 && new_size.height > 0 { - surface.resize( - &context, - NonZeroU32::new(new_size.width).unwrap(), - NonZeroU32::new(new_size.height).unwrap(), - ); - } - winit_platform.handle_event(imgui_context.io_mut(), &window, &event); - } - winit::event::Event::LoopExiting => { - let gl = ig_renderer.gl_context(); - tri_renderer.destroy(gl); - } - event => { - winit_platform.handle_event(imgui_context.io_mut(), &window, &event); - } - } - }) - .expect("EventLoop error"); -} diff --git a/imgui-glow-renderer/examples/glow_03_triangle_gles.rs b/imgui-glow-renderer/examples/glow_03_triangle_gles.rs deleted file mode 100644 index dcc4db4..0000000 --- a/imgui-glow-renderer/examples/glow_03_triangle_gles.rs +++ /dev/null @@ -1,108 +0,0 @@ -//! A basic example showing imgui rendering on top of a simple custom scene -//! using OpenGL ES, rather than full-fat OpenGL. -//! -//! Note this example uses `Renderer` rather than `AutoRenderer` and -//! therefore requries more lifetime-management of the OpenGL context. - -use std::{num::NonZeroU32, time::Instant}; - -mod utils; - -use glutin::{ - context::{ContextApi, Version}, - surface::GlSurface, -}; -use utils::Triangler; - -fn main() { - let (event_loop, window, surface, context) = utils::create_window( - "Hello, triangle! (GLES 3.0)", - Some(ContextApi::Gles(Some(Version::new(3, 0)))), - ); - let (mut winit_platform, mut imgui_context) = utils::imgui_init(&window); - let gl = utils::glow_context(&context); - - // When using `Renderer`, we need to create a texture map - let mut texture_map = imgui_glow_renderer::SimpleTextureMap::default(); - - // When using `Renderer`, we specify whether or not to output sRGB colors. - // Since we're drawing to screen and using OpenGL ES (which doesn't support - // `GL_FRAMEBUFFER_SRGB`) then we do need to convert to sRGB in the shader. - let mut ig_renderer = - imgui_glow_renderer::Renderer::initialize(&gl, &mut imgui_context, &mut texture_map, true) - .expect("failed to create renderer"); - // Note the shader header now needs a precision specifier - let tri_renderer = Triangler::new(&gl, "#version 300 es\nprecision mediump float;"); - - let mut last_frame = Instant::now(); - event_loop - .run(move |event, window_target| { - match event { - winit::event::Event::NewEvents(_) => { - let now = Instant::now(); - imgui_context - .io_mut() - .update_delta_time(now.duration_since(last_frame)); - last_frame = now; - } - winit::event::Event::AboutToWait => { - winit_platform - .prepare_frame(imgui_context.io_mut(), &window) - .unwrap(); - - window.request_redraw(); - } - winit::event::Event::WindowEvent { - event: winit::event::WindowEvent::RedrawRequested, - .. - } => { - // Draw custom scene - tri_renderer.render(&gl); - - let ui = imgui_context.frame(); - ui.show_demo_window(&mut true); - - winit_platform.prepare_render(ui, &window); - let draw_data = imgui_context.render(); - - // Render imgui on top - ig_renderer - .render(&gl, &texture_map, draw_data) - .expect("error rendering imgui"); - - surface - .swap_buffers(&context) - .expect("Failed to swap buffers"); - } - winit::event::Event::WindowEvent { - event: winit::event::WindowEvent::CloseRequested, - .. - } => { - window_target.exit(); - } - winit::event::Event::WindowEvent { - event: winit::event::WindowEvent::Resized(new_size), - .. - } => { - if new_size.width > 0 && new_size.height > 0 { - surface.resize( - &context, - NonZeroU32::new(new_size.width).unwrap(), - NonZeroU32::new(new_size.height).unwrap(), - ); - } - winit_platform.handle_event(imgui_context.io_mut(), &window, &event); - } - winit::event::Event::LoopExiting => { - tri_renderer.destroy(&gl); - // Note, to be good citizens we should manually call destroy - // when the renderer does not own the GL context - ig_renderer.destroy(&gl); - } - event => { - winit_platform.handle_event(imgui_context.io_mut(), &window, &event); - } - } - }) - .expect("EventLoop error"); -} diff --git a/imgui-glow-renderer/examples/glow_04_custom_textures.rs b/imgui-glow-renderer/examples/glow_04_custom_textures.rs deleted file mode 100644 index bdf9e99..0000000 --- a/imgui-glow-renderer/examples/glow_04_custom_textures.rs +++ /dev/null @@ -1,320 +0,0 @@ -//! Example showing the same functionality as -//! `imgui-examples/examples/custom_textures.rs` -//! -//! Not that the texture uses the internal format `glow::SRGB`, so that -//! OpenGL automatically converts colors to linear space before the shaders. -//! The renderer assumes you set this internal format correctly like this. - -use std::{io::Cursor, num::NonZeroU32, time::Instant}; - -use glow::HasContext; -use glutin::surface::GlSurface; -use image::{jpeg::JpegDecoder, ImageDecoder}; -use imgui::Condition; - -use imgui_glow_renderer::Renderer; -use winit::event_loop::ControlFlow; - -#[allow(dead_code)] -mod utils; - -const LENNA_JPEG: &[u8] = include_bytes!("../../resources/Lenna.jpg"); - -fn main() { - let (event_loop, window, surface, context) = utils::create_window("Custom textures", None); - let (mut winit_platform, mut imgui_context) = utils::imgui_init(&window); - let gl = utils::glow_context(&context); - // This time, we tell OpenGL this is an sRGB framebuffer and OpenGL will - // do the conversion to sSGB space for us after the fragment shader. - unsafe { gl.enable(glow::FRAMEBUFFER_SRGB) }; - - let mut textures = imgui::Textures::::default(); - // Note that `output_srgb` is `false`. This is because we set - // `glow::FRAMEBUFFER_SRGB` so we don't have to manually do the conversion - // in the shader. - let mut ig_renderer = Renderer::initialize(&gl, &mut imgui_context, &mut textures, false) - .expect("failed to create renderer"); - let textures_ui = TexturesUi::new(&gl, &mut textures); - - let mut last_frame = Instant::now(); - event_loop - .run(move |event, window_target| { - // Note we can potentially make the loop more efficient by - // changing the `Poll` (default) value to `ControlFlow::Wait` - // but be careful to test on all target platforms! - window_target.set_control_flow(ControlFlow::Poll); - - match event { - winit::event::Event::NewEvents(_) => { - let now = Instant::now(); - imgui_context - .io_mut() - .update_delta_time(now.duration_since(last_frame)); - last_frame = now; - } - winit::event::Event::AboutToWait => { - winit_platform - .prepare_frame(imgui_context.io_mut(), &window) - .unwrap(); - - window.request_redraw(); - } - winit::event::Event::WindowEvent { - event: winit::event::WindowEvent::RedrawRequested, - .. - } => { - unsafe { gl.clear(glow::COLOR_BUFFER_BIT) }; - - let ui = imgui_context.frame(); - textures_ui.show(ui); - - winit_platform.prepare_render(ui, &window); - let draw_data = imgui_context.render(); - ig_renderer - .render(&gl, &textures, draw_data) - .expect("error rendering imgui"); - - surface - .swap_buffers(&context) - .expect("Failed to swap buffers"); - } - winit::event::Event::WindowEvent { - event: winit::event::WindowEvent::Resized(new_size), - .. - } => { - if new_size.width > 0 && new_size.height > 0 { - surface.resize( - &context, - NonZeroU32::new(new_size.width).unwrap(), - NonZeroU32::new(new_size.height).unwrap(), - ); - } - winit_platform.handle_event(imgui_context.io_mut(), &window, &event); - } - winit::event::Event::WindowEvent { - event: winit::event::WindowEvent::CloseRequested, - .. - } => { - window_target.exit(); - } - winit::event::Event::LoopExiting => { - ig_renderer.destroy(&gl); - } - event => { - winit_platform.handle_event(imgui_context.io_mut(), &window, &event); - } - } - }) - .expect("EventLoop error"); -} - -struct TexturesUi { - generated_texture: imgui::TextureId, - lenna: Lenna, -} - -impl TexturesUi { - fn new(gl: &glow::Context, textures: &mut imgui::Textures) -> Self { - Self { - generated_texture: Self::generate(gl, textures), - lenna: Lenna::load(gl, textures), - } - } - - /// Generate dummy texture - fn generate( - gl: &glow::Context, - textures: &mut imgui::Textures, - ) -> imgui::TextureId { - const WIDTH: usize = 100; - const HEIGHT: usize = 100; - - let mut data = Vec::with_capacity(WIDTH * HEIGHT * 3); - for i in 0..WIDTH { - for j in 0..HEIGHT { - // Insert RGB values - data.push(i as u8); - data.push(j as u8); - data.push((i + j) as u8); - } - } - - let gl_texture = unsafe { gl.create_texture() }.expect("unable to create GL texture"); - - unsafe { - gl.bind_texture(glow::TEXTURE_2D, Some(gl_texture)); - gl.tex_parameter_i32( - glow::TEXTURE_2D, - glow::TEXTURE_MIN_FILTER, - glow::LINEAR as _, - ); - gl.tex_parameter_i32( - glow::TEXTURE_2D, - glow::TEXTURE_MAG_FILTER, - glow::LINEAR as _, - ); - gl.tex_image_2d( - glow::TEXTURE_2D, - 0, - glow::RGB as _, // When generating a texture like this, you're probably working in linear color space - WIDTH as _, - HEIGHT as _, - 0, - glow::RGB, - glow::UNSIGNED_BYTE, - Some(&data), - ) - } - - textures.insert(gl_texture) - } - - fn show(&self, ui: &imgui::Ui) { - ui.window("Hello textures") - .size([400.0, 400.0], Condition::FirstUseEver) - .build(|| { - ui.text("Hello textures!"); - ui.text("Some generated texture"); - imgui::Image::new(self.generated_texture, [100.0, 100.0]).build(ui); - - ui.text("Say hello to Lenna.jpg"); - self.lenna.show(ui); - - // Example of using custom textures on a button - ui.text("The Lenna buttons"); - { - ui.invisible_button("Boring Button", [100.0, 100.0]); - // See also `imgui::Ui::style_color` - let tint_none = [1.0, 1.0, 1.0, 1.0]; - let tint_green = [0.5, 1.0, 0.5, 1.0]; - let tint_red = [1.0, 0.5, 0.5, 1.0]; - - let tint = match ( - ui.is_item_hovered(), - ui.is_mouse_down(imgui::MouseButton::Left), - ) { - (false, _) => tint_none, - (true, false) => tint_green, - (true, true) => tint_red, - }; - - let draw_list = ui.get_window_draw_list(); - draw_list - .add_image( - self.lenna.texture_id, - ui.item_rect_min(), - ui.item_rect_max(), - ) - .col(tint) - .build(); - } - - { - ui.same_line(); - - // Button using quad positioned image - ui.invisible_button("Exciting Button", [100.0, 100.0]); - - // Button bounds - let min = ui.item_rect_min(); - let max = ui.item_rect_max(); - - // get corner coordinates - let tl = [ - min[0], - min[1] + (ui.frame_count() as f32 / 10.0).cos() * 10.0, - ]; - let tr = [ - max[0], - min[1] + (ui.frame_count() as f32 / 10.0).sin() * 10.0, - ]; - let bl = [min[0], max[1]]; - let br = max; - - let draw_list = ui.get_window_draw_list(); - draw_list - .add_image_quad(self.lenna.texture_id, tl, tr, br, bl) - .build(); - } - - // Rounded image - { - ui.same_line(); - ui.invisible_button("Smooth Button", [100.0, 100.0]); - - let draw_list = ui.get_window_draw_list(); - draw_list - .add_image_rounded( - self.lenna.texture_id, - ui.item_rect_min(), - ui.item_rect_max(), - 16.0, - ) - // Tint brighter for visiblity of corners - .col([2.0, 0.5, 0.5, 1.0]) - // Rounding on each corner can be changed separately - .round_top_left(ui.frame_count() / 60 % 4 == 0) - .round_top_right((ui.frame_count() + 1) / 60 % 4 == 1) - .round_bot_right((ui.frame_count() + 3) / 60 % 4 == 2) - .round_bot_left((ui.frame_count() + 2) / 60 % 4 == 3) - .build(); - } - }); - } -} - -struct Lenna { - texture_id: imgui::TextureId, - size: [f32; 2], -} - -impl Lenna { - fn load(gl: &glow::Context, textures: &mut imgui::Textures) -> Self { - let decoder = JpegDecoder::new(Cursor::new(LENNA_JPEG)).expect("could not create decoder"); - let (width, height) = decoder.dimensions(); - - let lenna_image = { - let mut bytes = vec![0; decoder.total_bytes() as usize]; - decoder - .read_image(&mut bytes) - .expect("unable to decode jpeg"); - bytes - }; - - let gl_texture = unsafe { gl.create_texture() }.expect("unable to create GL texture"); - - unsafe { - gl.bind_texture(glow::TEXTURE_2D, Some(gl_texture)); - gl.tex_parameter_i32( - glow::TEXTURE_2D, - glow::TEXTURE_MIN_FILTER, - glow::LINEAR as _, - ); - gl.tex_parameter_i32( - glow::TEXTURE_2D, - glow::TEXTURE_MAG_FILTER, - glow::LINEAR as _, - ); - gl.tex_image_2d( - glow::TEXTURE_2D, - 0, - glow::SRGB as _, // image file has sRGB encoded colors - width as _, - height as _, - 0, - glow::RGB, - glow::UNSIGNED_BYTE, - Some(&lenna_image), - ) - } - - Self { - texture_id: textures.insert(gl_texture), - size: [width as _, height as _], - } - } - - fn show(&self, ui: &imgui::Ui) { - imgui::Image::new(self.texture_id, self.size).build(ui); - } -} diff --git a/imgui-glow-renderer/examples/glow_05_framebufferobject.rs b/imgui-glow-renderer/examples/glow_05_framebufferobject.rs deleted file mode 100644 index b1b9e49..0000000 --- a/imgui-glow-renderer/examples/glow_05_framebufferobject.rs +++ /dev/null @@ -1,179 +0,0 @@ -//! A basic example showing imgui rendering on top of a simple custom scene. - -use std::{cell::RefCell, num::NonZeroU32, rc::Rc, time::Instant}; - -mod utils; - -use glow::HasContext; -use glutin::surface::GlSurface; -use utils::Triangler; - -struct UserData { - gl: Rc, - fbo: glow::NativeFramebuffer, - _rbo: glow::NativeRenderbuffer, -} - -const FBO_SIZE: i32 = 128; - -fn main() { - let (event_loop, window, surface, context) = utils::create_window("Hello, FBO!", None); - let (mut winit_platform, mut imgui_context) = utils::imgui_init(&window); - let gl = utils::glow_context(&context); - - let mut ig_renderer = imgui_glow_renderer::AutoRenderer::initialize(gl, &mut imgui_context) - .expect("failed to create renderer"); - let tri_renderer = Triangler::new(ig_renderer.gl_context(), "#version 330"); - - let fbo; - let rbo; - unsafe { - let gl = ig_renderer.gl_context(); - fbo = gl.create_framebuffer().unwrap(); - rbo = gl.create_renderbuffer().unwrap(); - - gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(fbo)); - gl.bind_renderbuffer(glow::RENDERBUFFER, Some(rbo)); - gl.renderbuffer_storage(glow::RENDERBUFFER, glow::RGBA8, FBO_SIZE, FBO_SIZE); - gl.framebuffer_renderbuffer( - glow::DRAW_FRAMEBUFFER, - glow::COLOR_ATTACHMENT0, - glow::RENDERBUFFER, - Some(rbo), - ); - gl.bind_renderbuffer(glow::RENDERBUFFER, None); - - gl.viewport(0, 0, FBO_SIZE, FBO_SIZE); - tri_renderer.render(gl); - - gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None); - } - - let data = Rc::new(RefCell::new(UserData { - gl: Rc::clone(ig_renderer.gl_context()), - fbo, - _rbo: rbo, - })); - - let mut last_frame = Instant::now(); - event_loop - .run(move |event, window_target| { - match event { - winit::event::Event::NewEvents(_) => { - let now = Instant::now(); - imgui_context - .io_mut() - .update_delta_time(now.duration_since(last_frame)); - last_frame = now; - } - winit::event::Event::AboutToWait => { - winit_platform - .prepare_frame(imgui_context.io_mut(), &window) - .unwrap(); - - window.request_redraw(); - } - winit::event::Event::WindowEvent { - event: winit::event::WindowEvent::RedrawRequested, - .. - } => { - // Render your custom scene, note we need to borrow the OpenGL - // context from the `AutoRenderer`, which takes ownership of it. - unsafe { - ig_renderer.gl_context().clear(glow::COLOR_BUFFER_BIT); - } - - let ui = imgui_context.frame(); - ui.show_demo_window(&mut true); - ui.window("FBO").resizable(false).build(|| { - let pos = ui.cursor_screen_pos(); - ui.set_cursor_screen_pos([ - pos[0] + FBO_SIZE as f32, - pos[1] + FBO_SIZE as f32, - ]); - - let draws = ui.get_window_draw_list(); - let scale = ui.io().display_framebuffer_scale; - let dsp_size = ui.io().display_size; - draws - .add_callback({ - let data = Rc::clone(&data); - move || { - let data = data.borrow(); - let gl = &*data.gl; - unsafe { - let x = pos[0] * scale[0]; - let y = (dsp_size[1] - pos[1]) * scale[1]; - let dst_x0 = x as i32; - let dst_y0 = (y - FBO_SIZE as f32 * scale[1]) as i32; - let dst_x1 = (x + FBO_SIZE as f32 * scale[0]) as i32; - let dst_y1 = y as i32; - gl.scissor( - dst_x0, - dst_y0, - dst_x1 - dst_x0, - dst_y1 - dst_y0, - ); - gl.enable(glow::SCISSOR_TEST); - gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(data.fbo)); - gl.blit_framebuffer( - 0, - 0, - FBO_SIZE, - FBO_SIZE, - dst_x0, - dst_y0, - dst_x1, - dst_y1, - glow::COLOR_BUFFER_BIT, - glow::NEAREST, - ); - gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None); - } - } - }) - .build(); - }); - - winit_platform.prepare_render(ui, &window); - let draw_data = imgui_context.render(); - - // Render imgui on top of it - ig_renderer - .render(draw_data) - .expect("error rendering imgui"); - - surface - .swap_buffers(&context) - .expect("Failed to swap buffers"); - } - winit::event::Event::WindowEvent { - event: winit::event::WindowEvent::CloseRequested, - .. - } => { - window_target.exit(); - } - winit::event::Event::WindowEvent { - event: winit::event::WindowEvent::Resized(new_size), - .. - } => { - if new_size.width > 0 && new_size.height > 0 { - surface.resize( - &context, - NonZeroU32::new(new_size.width).unwrap(), - NonZeroU32::new(new_size.height).unwrap(), - ); - } - winit_platform.handle_event(imgui_context.io_mut(), &window, &event); - } - winit::event::Event::LoopExiting => { - let gl = ig_renderer.gl_context(); - tri_renderer.destroy(gl); - } - event => { - winit_platform.handle_event(imgui_context.io_mut(), &window, &event); - } - } - }) - .expect("EventLoop error"); -} diff --git a/imgui-glow-renderer/examples/utils/mod.rs b/imgui-glow-renderer/examples/utils/mod.rs deleted file mode 100644 index b1a7b78..0000000 --- a/imgui-glow-renderer/examples/utils/mod.rs +++ /dev/null @@ -1,215 +0,0 @@ -use std::num::NonZeroU32; - -use glow::HasContext; -use glutin::{ - config::ConfigTemplateBuilder, - context::{ContextApi, ContextAttributesBuilder, NotCurrentGlContext, PossiblyCurrentContext}, - display::{GetGlDisplay, GlDisplay}, - surface::{GlSurface, Surface, SurfaceAttributesBuilder, SwapInterval, WindowSurface}, -}; -use imgui_winit_support::WinitPlatform; -use raw_window_handle::HasRawWindowHandle; -use winit::{ - dpi::LogicalSize, - event_loop::EventLoop, - window::{Window, WindowBuilder}, -}; - -pub fn create_window( - title: &str, - context_api: Option, -) -> ( - EventLoop<()>, - Window, - Surface, - PossiblyCurrentContext, -) { - let event_loop = EventLoop::new().unwrap(); - - let window_builder = WindowBuilder::new() - .with_title(title) - .with_inner_size(LogicalSize::new(1024, 768)); - let (window, cfg) = glutin_winit::DisplayBuilder::new() - .with_window_builder(Some(window_builder)) - .build(&event_loop, ConfigTemplateBuilder::new(), |mut configs| { - configs.next().unwrap() - }) - .expect("Failed to create OpenGL window"); - - let window = window.unwrap(); - - let mut context_attribs = ContextAttributesBuilder::new(); - if let Some(context_api) = context_api { - context_attribs = context_attribs.with_context_api(context_api); - } - let context_attribs = context_attribs.build(Some(window.raw_window_handle())); - let context = unsafe { - cfg.display() - .create_context(&cfg, &context_attribs) - .expect("Failed to create OpenGL context") - }; - - let surface_attribs = SurfaceAttributesBuilder::::new() - .with_srgb(Some(true)) - .build( - window.raw_window_handle(), - NonZeroU32::new(1024).unwrap(), - NonZeroU32::new(768).unwrap(), - ); - let surface = unsafe { - cfg.display() - .create_window_surface(&cfg, &surface_attribs) - .expect("Failed to create OpenGL surface") - }; - - let context = context - .make_current(&surface) - .expect("Failed to make OpenGL context current"); - - surface - .set_swap_interval(&context, SwapInterval::Wait(NonZeroU32::new(1).unwrap())) - .expect("Failed to set swap interval"); - - (event_loop, window, surface, context) -} - -pub fn glow_context(context: &PossiblyCurrentContext) -> glow::Context { - unsafe { - glow::Context::from_loader_function_cstr(|s| context.display().get_proc_address(s).cast()) - } -} - -pub fn imgui_init(window: &Window) -> (WinitPlatform, imgui::Context) { - let mut imgui_context = imgui::Context::create(); - imgui_context.set_ini_filename(None); - - let mut winit_platform = WinitPlatform::init(&mut imgui_context); - winit_platform.attach_window( - imgui_context.io_mut(), - window, - imgui_winit_support::HiDpiMode::Rounded, - ); - - imgui_context - .fonts() - .add_font(&[imgui::FontSource::DefaultFontData { config: None }]); - - imgui_context.io_mut().font_global_scale = (1.0 / winit_platform.hidpi_factor()) as f32; - - (winit_platform, imgui_context) -} - -pub struct Triangler { - pub program: ::Program, - pub vertex_array: ::VertexArray, -} - -impl Triangler { - pub fn new(gl: &glow::Context, shader_header: &str) -> Self { - const VERTEX_SHADER_SOURCE: &str = r#" -const vec2 verts[3] = vec2[3]( - vec2(0.5f, 1.0f), - vec2(0.0f, 0.0f), - vec2(1.0f, 0.0f) -); - -out vec2 vert; -out vec4 color; - -vec4 srgb_to_linear(vec4 srgb_color) { - // Calcuation as documented by OpenGL - vec3 srgb = srgb_color.rgb; - vec3 selector = ceil(srgb - 0.04045); - vec3 less_than_branch = srgb / 12.92; - vec3 greater_than_branch = pow((srgb + 0.055) / 1.055, vec3(2.4)); - return vec4( - mix(less_than_branch, greater_than_branch, selector), - srgb_color.a - ); -} - -void main() { - vert = verts[gl_VertexID]; - color = srgb_to_linear(vec4(vert, 0.5, 1.0)); - gl_Position = vec4(vert - 0.5, 0.0, 1.0); -} -"#; - const FRAGMENT_SHADER_SOURCE: &str = r#" -in vec2 vert; -in vec4 color; - -out vec4 frag_color; - -vec4 linear_to_srgb(vec4 linear_color) { - vec3 linear = linear_color.rgb; - vec3 selector = ceil(linear - 0.0031308); - vec3 less_than_branch = linear * 12.92; - vec3 greater_than_branch = pow(linear, vec3(1.0/2.4)) * 1.055 - 0.055; - return vec4( - mix(less_than_branch, greater_than_branch, selector), - linear_color.a - ); -} - -void main() { - frag_color = linear_to_srgb(color); -} -"#; - - let mut shaders = [ - (glow::VERTEX_SHADER, VERTEX_SHADER_SOURCE, None), - (glow::FRAGMENT_SHADER, FRAGMENT_SHADER_SOURCE, None), - ]; - - unsafe { - let vertex_array = gl - .create_vertex_array() - .expect("Cannot create vertex array"); - - let program = gl.create_program().expect("Cannot create program"); - - for (kind, source, handle) in &mut shaders { - let shader = gl.create_shader(*kind).expect("Cannot create shader"); - gl.shader_source(shader, &format!("{}\n{}", shader_header, *source)); - gl.compile_shader(shader); - if !gl.get_shader_compile_status(shader) { - panic!("{}", gl.get_shader_info_log(shader)); - } - gl.attach_shader(program, shader); - *handle = Some(shader); - } - - gl.link_program(program); - if !gl.get_program_link_status(program) { - panic!("{}", gl.get_program_info_log(program)); - } - - for &(_, _, shader) in &shaders { - gl.detach_shader(program, shader.unwrap()); - gl.delete_shader(shader.unwrap()); - } - - Self { - program, - vertex_array, - } - } - } - - pub fn render(&self, gl: &glow::Context) { - unsafe { - gl.clear_color(0.05, 0.05, 0.1, 1.0); - gl.clear(glow::COLOR_BUFFER_BIT); - gl.use_program(Some(self.program)); - gl.bind_vertex_array(Some(self.vertex_array)); - gl.draw_arrays(glow::TRIANGLES, 0, 3); - } - } - - pub fn destroy(&self, gl: &glow::Context) { - unsafe { - gl.delete_program(self.program); - gl.delete_vertex_array(self.vertex_array); - } - } -} diff --git a/imgui-glow-renderer/src/lib.rs b/imgui-glow-renderer/src/lib.rs deleted file mode 100644 index 4b70cc6..0000000 --- a/imgui-glow-renderer/src/lib.rs +++ /dev/null @@ -1,1164 +0,0 @@ -//! Renderer for [`imgui-rs`][imgui] using the [`glow`] library for OpenGL. -//! -//! This is heavily influenced by the -//! [example from upstream](https://github.com/ocornut/imgui/blob/fe245914114588f272b0924538fdd43f6c127a26/backends/imgui_impl_opengl3.cpp). -//! -//! # Basic usage -//! -//! A few code [examples] are provided in the source. -//! -//! [examples]: https://github.com/imgui-rs/imgui-rs/tree/main/imgui-glow-renderer/examples -//! -//! In short, create either an [`AutoRenderer`] (for basic usage) or [`Renderer`] -//! (for slightly more customizable operation), then call the `render(...)` -//! method with draw data from [`imgui`]. -//! -//! # OpenGL (ES) versions -//! -//! This renderer is expected to work with OpenGL version 3.3 and above, and -//! OpenGL ES version 3.0 or above. This should cover the vast majority of even -//! fairly dated hardware. Please submit an issue for any incompatibilities -//! found with these OpenGL versions, pull requests to extend support to earlier -//! versions are welcomed. -//! -//! # Scope -//! -//! Consider this an example renderer. It is intended to be sufficent for simple -//! applications running imgui-rs as the final rendering step. If your application -//! has more specific needs, it's probably best to write your own renderer, in -//! which case this can be a useful starting point. This renderer is also not -//! foolproof (largely due to the global nature of the OpenGL state). For example, -//! a few "internal" functions are marked `pub` to allow the user more -//! fine-grained control at the cost of allowing potential rendering errors. -//! -//! # sRGB -//! -//! When outputting colors to a screen, colors need to be converted from a -//! linear color space to a non-linear space matching the monitor (e.g. sRGB). -//! When using the [`AutoRenderer`], this library will convert colors to sRGB -//! as a step in the shader. When initialising a [`Renderer`], you can choose -//! whether or not to include this step in the shader or not when calling -//! [`Renderer::initialize`]. -//! -//! This library also assumes that textures have their internal format -//! set appropriately when uploaded to OpenGL. That is, assuming your texture -//! is sRGB (if you don't know, it probably is) the `internal_format` is -//! one of the `SRGB*` values. - -use std::{borrow::Cow, error::Error, fmt::Display, mem::size_of, num::NonZeroU32, rc::Rc}; - -use imgui::{internal::RawWrapper, DrawCmd, DrawData, DrawVert}; - -use crate::versions::{GlVersion, GlslVersion}; - -// Re-export glow to make it easier for users to use the correct version. -pub use glow; -use glow::{Context, HasContext}; - -pub mod versions; - -pub type GlBuffer = ::Buffer; -pub type GlTexture = ::Texture; -pub type GlVertexArray = ::VertexArray; -type GlProgram = ::Program; -type GlUniformLocation = ::UniformLocation; - -/// Renderer which owns the OpenGL context and handles textures itself. Also -/// converts all output colors to sRGB for display. Useful for simple applications, -/// but more complicated applications may prefer to use [`Renderer`], or even -/// write their own renderer based on this code. -/// -/// OpenGL context is still available to the rest of the application through -/// the [`gl_context`](Self::gl_context) method. -pub struct AutoRenderer { - gl: Rc, - texture_map: SimpleTextureMap, - renderer: Renderer, -} - -impl AutoRenderer { - /// # Errors - /// Any error initialising the OpenGL objects (including shaders) will - /// result in an error. - pub fn initialize( - gl: glow::Context, - imgui_context: &mut imgui::Context, - ) -> Result { - let mut texture_map = SimpleTextureMap::default(); - let renderer = Renderer::initialize(&gl, imgui_context, &mut texture_map, true)?; - Ok(Self { - gl: Rc::new(gl), - texture_map, - renderer, - }) - } - - /// Note: no need to provide a `mut` version of this, as all methods on - /// [`glow::HasContext`] are immutable. - #[inline] - pub fn gl_context(&self) -> &Rc { - &self.gl - } - - #[inline] - pub fn texture_map(&self) -> &SimpleTextureMap { - &self.texture_map - } - - #[inline] - pub fn texture_map_mut(&mut self) -> &mut SimpleTextureMap { - &mut self.texture_map - } - - #[inline] - pub fn renderer(&self) -> &Renderer { - &self.renderer - } - - /// # Errors - /// Some OpenGL errors trigger an error (few are explicitly checked, - /// however) - #[inline] - pub fn render(&mut self, draw_data: &DrawData) -> Result<(), RenderError> { - self.renderer.render(&self.gl, &self.texture_map, draw_data) - } -} - -impl Drop for AutoRenderer { - fn drop(&mut self) { - self.renderer.destroy(&self.gl); - } -} - -/// Main renderer. Borrows the OpenGL context and [texture map](TextureMap) -/// when required. -pub struct Renderer { - shaders: Shaders, - state_backup: GlStateBackup, - pub vbo_handle: Option, - pub ebo_handle: Option, - pub font_atlas_texture: Option, - #[cfg(feature = "bind_vertex_array_support")] - pub vertex_array_object: Option, - pub gl_version: GlVersion, - pub has_clip_origin_support: bool, - pub is_destroyed: bool, -} - -impl Renderer { - /// Create the renderer, initialising OpenGL objects and shaders. - /// - /// `output_srgb` controls whether the shader outputs sRGB colors, or linear - /// RGB colors. In short: - /// - If you're outputting to a display and haven't specified the framebuffer - /// is sRGB (e.g. with `gl.enable(glow::FRAMEBUFFER_SRGB)`), then you probably - /// want `output_srgb=true`. - /// - OpenGL ES doesn't support sRGB framebuffers, so you almost always - /// want `output_srgb=true` if you're using OpenGL ES and you're outputting - /// to a display. - /// - If you're outputting to a display with an sRGB framebuffer (e.g. with - /// `gl.enable(glow::FRAMEBUFFER_SRGB)`), then you probably want - /// `output_srgb=false`, as OpenGL will convert to sRGB itself. - /// - If you're not outputting to a display, but instead to some intermediate - /// framebuffer, then you probably want `output_srgb=false` to keep the - /// colors in linear color space, and then convert them to sRGB at some - /// later stage. - /// - /// # Errors - /// Any error initialising the OpenGL objects (including shaders) will - /// result in an error. - pub fn initialize( - gl: &Context, - imgui_context: &mut imgui::Context, - texture_map: &mut T, - output_srgb: bool, - ) -> Result { - #![allow( - clippy::similar_names, - clippy::cast_sign_loss, - clippy::shadow_unrelated - )] - - let gl_version = GlVersion::read(gl); - - #[cfg(feature = "clip_origin_support")] - let has_clip_origin_support = { - let support = gl_version.clip_origin_support(); - - #[cfg(feature = "gl_extensions_support")] - if support { - support - } else { - let extensions_count = unsafe { gl.get_parameter_i32(glow::NUM_EXTENSIONS) } as u32; - (0..extensions_count).any(|index| { - let extension_name = - unsafe { gl.get_parameter_indexed_string(glow::EXTENSIONS, index) }; - extension_name == "GL_ARB_clip_control" - }) - } - #[cfg(not(feature = "gl_extensions_support"))] - support - }; - #[cfg(not(feature = "clip_origin_support"))] - let has_clip_origin_support = false; - - let mut state_backup = GlStateBackup::default(); - state_backup.pre_init(gl); - - let font_atlas_texture = prepare_font_atlas(gl, imgui_context.fonts(), texture_map)?; - - let shaders = Shaders::new(gl, gl_version, output_srgb)?; - let vbo_handle = unsafe { gl.create_buffer() }.map_err(InitError::CreateBufferObject)?; - let ebo_handle = unsafe { gl.create_buffer() }.map_err(InitError::CreateBufferObject)?; - - state_backup.post_init(gl); - - let out = Self { - shaders, - state_backup, - vbo_handle: Some(vbo_handle), - ebo_handle: Some(ebo_handle), - font_atlas_texture: Some(font_atlas_texture), - #[cfg(feature = "bind_vertex_array_support")] - vertex_array_object: None, - gl_version, - has_clip_origin_support, - is_destroyed: false, - }; - - // Leave this until the end of the function to avoid changing state if - // there was ever an error above - out.configure_imgui_context(imgui_context); - - Ok(out) - } - - /// This must be called before being dropped to properly free OpenGL - /// resources. - pub fn destroy(&mut self, gl: &Context) { - if self.is_destroyed { - return; - } - - if let Some(h) = self.vbo_handle { - unsafe { gl.delete_buffer(h) }; - self.vbo_handle = None; - } - if let Some(h) = self.ebo_handle { - unsafe { gl.delete_buffer(h) }; - self.ebo_handle = None; - } - if let Some(p) = self.shaders.program { - unsafe { gl.delete_program(p) }; - self.shaders.program = None; - } - if let Some(h) = self.font_atlas_texture { - unsafe { gl.delete_texture(h) }; - self.font_atlas_texture = None; - } - - self.is_destroyed = true; - } - - /// # Errors - /// Some OpenGL errors trigger an error (few are explicitly checked, - /// however) - pub fn render( - &mut self, - gl: &Context, - texture_map: &T, - draw_data: &DrawData, - ) -> Result<(), RenderError> { - if self.is_destroyed { - return Err(Self::renderer_destroyed()); - } - - let fb_width = draw_data.display_size[0] * draw_data.framebuffer_scale[0]; - let fb_height = draw_data.display_size[1] * draw_data.framebuffer_scale[1]; - if !(fb_width > 0.0 && fb_height > 0.0) { - return Ok(()); - } - - gl_debug_message(gl, "imgui-rs-glow: start render"); - self.state_backup.pre_render(gl, self.gl_version); - - #[cfg(feature = "bind_vertex_array_support")] - if self.gl_version.bind_vertex_array_support() { - unsafe { - self.vertex_array_object = Some( - gl.create_vertex_array() - .map_err(|err| format!("Error creating vertex array object: {}", err))?, - ); - gl.bind_vertex_array(self.vertex_array_object); - } - } - - self.set_up_render_state(gl, draw_data, fb_width, fb_height)?; - - gl_debug_message(gl, "start loop over draw lists"); - for draw_list in draw_data.draw_lists() { - unsafe { - gl.buffer_data_u8_slice( - glow::ARRAY_BUFFER, - to_byte_slice(draw_list.vtx_buffer()), - glow::STREAM_DRAW, - ); - gl.buffer_data_u8_slice( - glow::ELEMENT_ARRAY_BUFFER, - to_byte_slice(draw_list.idx_buffer()), - glow::STREAM_DRAW, - ); - } - - gl_debug_message(gl, "start loop over commands"); - for command in draw_list.commands() { - match command { - DrawCmd::Elements { count, cmd_params } => self.render_elements( - gl, - texture_map, - count, - cmd_params, - draw_data, - fb_width, - fb_height, - ), - DrawCmd::RawCallback { callback, raw_cmd } => unsafe { - callback(draw_list.raw(), raw_cmd) - }, - DrawCmd::ResetRenderState => { - self.set_up_render_state(gl, draw_data, fb_width, fb_height)? - } - } - } - } - - #[cfg(feature = "bind_vertex_array_support")] - if self.gl_version.bind_vertex_array_support() { - unsafe { gl.delete_vertex_array(self.vertex_array_object.unwrap()) }; - self.vertex_array_object = None; - } - - self.state_backup.post_render(gl, self.gl_version); - gl_debug_message(gl, "imgui-rs-glow: complete render"); - Ok(()) - } - - /// # Errors - /// Few GL calls are checked for errors, but any that are found will result - /// in an error. Errors from the state manager lifecycle callbacks will also - /// result in an error. - pub fn set_up_render_state( - &mut self, - gl: &Context, - draw_data: &DrawData, - fb_width: f32, - fb_height: f32, - ) -> Result<(), RenderError> { - #![allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)] - - if self.is_destroyed { - return Err(Self::renderer_destroyed()); - } - - unsafe { - gl.active_texture(glow::TEXTURE0); - gl.enable(glow::BLEND); - gl.blend_equation(glow::FUNC_ADD); - gl.blend_func_separate( - glow::SRC_ALPHA, - glow::ONE_MINUS_SRC_ALPHA, - glow::ONE, - glow::ONE_MINUS_SRC_ALPHA, - ); - gl.disable(glow::CULL_FACE); - gl.disable(glow::DEPTH_TEST); - gl.disable(glow::STENCIL_TEST); - gl.enable(glow::SCISSOR_TEST); - - #[cfg(feature = "primitive_restart_support")] - if self.gl_version.primitive_restart_support() { - gl.disable(glow::PRIMITIVE_RESTART); - } - - #[cfg(feature = "polygon_mode_support")] - if self.gl_version.polygon_mode_support() { - gl.polygon_mode(glow::FRONT_AND_BACK, glow::FILL); - } - - gl.viewport(0, 0, fb_width as _, fb_height as _); - } - - #[cfg(feature = "clip_origin_support")] - let clip_origin_is_lower_left = if self.has_clip_origin_support { - unsafe { gl.get_parameter_i32(glow::CLIP_ORIGIN) != glow::UPPER_LEFT as i32 } - } else { - true - }; - #[cfg(not(feature = "clip_origin_support"))] - let clip_origin_is_lower_left = true; - - let projection_matrix = calculate_matrix(draw_data, clip_origin_is_lower_left); - - unsafe { - gl.use_program(self.shaders.program); - gl.uniform_1_i32(Some(&self.shaders.texture_uniform_location), 0); - gl.uniform_matrix_4_f32_slice( - Some(&self.shaders.matrix_uniform_location), - false, - &projection_matrix, - ); - } - - #[cfg(feature = "bind_sampler_support")] - if self.gl_version.bind_sampler_support() { - unsafe { gl.bind_sampler(0, None) }; - } - - // TODO: soon it should be possible for these to be `const` functions - let position_field_offset = memoffset::offset_of!(DrawVert, pos) as _; - let uv_field_offset = memoffset::offset_of!(DrawVert, uv) as _; - let color_field_offset = memoffset::offset_of!(DrawVert, col) as _; - - unsafe { - gl.bind_buffer(glow::ARRAY_BUFFER, self.vbo_handle); - gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, self.ebo_handle); - gl.enable_vertex_attrib_array(self.shaders.position_attribute_index); - gl.vertex_attrib_pointer_f32( - self.shaders.position_attribute_index, - 2, - glow::FLOAT, - false, - size_of::() as _, - position_field_offset, - ); - gl.enable_vertex_attrib_array(self.shaders.uv_attribute_index); - gl.vertex_attrib_pointer_f32( - self.shaders.uv_attribute_index, - 2, - glow::FLOAT, - false, - size_of::() as _, - uv_field_offset, - ); - gl.enable_vertex_attrib_array(self.shaders.color_attribute_index); - gl.vertex_attrib_pointer_f32( - self.shaders.color_attribute_index, - 4, - glow::UNSIGNED_BYTE, - true, - size_of::() as _, - color_field_offset, - ); - } - - Ok(()) - } - - #[allow(clippy::too_many_arguments)] - fn render_elements( - &self, - gl: &Context, - texture_map: &T, - element_count: usize, - element_params: imgui::DrawCmdParams, - draw_data: &DrawData, - fb_width: f32, - fb_height: f32, - ) { - #![allow( - clippy::similar_names, - clippy::cast_possible_truncation, - clippy::cast_possible_wrap - )] - - let imgui::DrawCmdParams { - clip_rect, - texture_id, - vtx_offset, - idx_offset, - } = element_params; - let clip_off = draw_data.display_pos; - let scale = draw_data.framebuffer_scale; - - let clip_x1 = (clip_rect[0] - clip_off[0]) * scale[0]; - let clip_y1 = (clip_rect[1] - clip_off[1]) * scale[1]; - let clip_x2 = (clip_rect[2] - clip_off[0]) * scale[0]; - let clip_y2 = (clip_rect[3] - clip_off[1]) * scale[1]; - - if clip_x1 >= fb_width || clip_y1 >= fb_height || clip_x2 < 0.0 || clip_y2 < 0.0 { - return; - } - - unsafe { - gl.scissor( - clip_x1 as i32, - (fb_height - clip_y2) as i32, - (clip_x2 - clip_x1) as i32, - (clip_y2 - clip_y1) as i32, - ); - gl.bind_texture(glow::TEXTURE_2D, texture_map.gl_texture(texture_id)); - - #[cfg(feature = "vertex_offset_support")] - let with_offset = self.gl_version.vertex_offset_support(); - #[cfg(not(feature = "vertex_offset_support"))] - let with_offset = false; - - if with_offset { - gl.draw_elements_base_vertex( - glow::TRIANGLES, - element_count as _, - imgui_index_type_as_gl(), - (idx_offset * size_of::()) as _, - vtx_offset as _, - ); - } else { - gl.draw_elements( - glow::TRIANGLES, - element_count as _, - imgui_index_type_as_gl(), - (idx_offset * size_of::()) as _, - ); - } - } - } - - fn configure_imgui_context(&self, imgui_context: &mut imgui::Context) { - imgui_context.set_renderer_name(Some(format!( - "imgui-rs-glow-render {}", - env!("CARGO_PKG_VERSION") - ))); - - #[cfg(feature = "vertex_offset_support")] - if self.gl_version.vertex_offset_support() { - imgui_context - .io_mut() - .backend_flags - .insert(imgui::BackendFlags::RENDERER_HAS_VTX_OFFSET); - } - } - - fn renderer_destroyed() -> RenderError { - "Renderer is destroyed".into() - } -} - -/// Trait for mapping imgui texture IDs to OpenGL textures. -/// -/// [`register`] should be called after uploading a texture to OpenGL to get a -/// [`imgui::TextureId`] corresponding to it. -/// -/// [`register`]: Self::register -/// -/// Then [`gl_texture`] can be called to find the OpenGL texture corresponding to -/// that [`imgui::TextureId`]. -/// -/// [`gl_texture`]: Self::gl_texture -pub trait TextureMap { - fn register(&mut self, gl_texture: GlTexture) -> Option; - - fn gl_texture(&self, imgui_texture: imgui::TextureId) -> Option; -} - -/// Texture map where the imgui texture ID is simply numerically equal to the -/// OpenGL texture ID. -#[derive(Default)] -pub struct SimpleTextureMap(); - -impl TextureMap for SimpleTextureMap { - #[inline(always)] - fn register(&mut self, gl_texture: glow::Texture) -> Option { - Some(imgui::TextureId::new(gl_texture.0.get() as _)) - } - - #[inline(always)] - fn gl_texture(&self, imgui_texture: imgui::TextureId) -> Option { - #[allow(clippy::cast_possible_truncation)] - Some(glow::NativeTexture( - NonZeroU32::new(imgui_texture.id() as _).unwrap(), - )) - } -} - -/// [`imgui::Textures`] is a simple choice for a texture map. -impl TextureMap for imgui::Textures { - fn register(&mut self, gl_texture: glow::Texture) -> Option { - Some(self.insert(gl_texture)) - } - - fn gl_texture(&self, imgui_texture: imgui::TextureId) -> Option { - self.get(imgui_texture).copied() - } -} - -/// This OpenGL state backup is based on the upstream OpenGL example from -/// imgui, where an attempt is made to save and restore the OpenGL context state -/// before and after rendering. -/// -/// If you're writing your own renderer, you can likely streamline most of this. -/// -/// It is unlikely that any such attempt will be comprehensive for all possible -/// applications, due to the complexity of OpenGL and the possibility of -/// arbitrary extensions. However, it remains as a useful tool for quickly -/// getting started. If your application needs more state to be backed up and -/// restored, it is probably best to do this manually before/after calling -/// the render method rather than opening an issue to add more to this -/// struct. -#[allow(clippy::struct_excessive_bools)] -#[derive(Default)] -pub struct GlStateBackup { - active_texture: u32, - program: u32, - texture: u32, - #[cfg(feature = "bind_sampler_support")] - sampler: Option, - array_buffer: u32, - #[cfg(feature = "polygon_mode_support")] - polygon_mode: Option<[i32; 2]>, - viewport: [i32; 4], - scissor_box: [i32; 4], - blend_src_rgb: i32, - blend_dst_rgb: i32, - blend_src_alpha: i32, - blend_dst_alpha: i32, - blend_equation_rgb: i32, - blend_equation_alpha: i32, - blend_enabled: bool, - cull_face_enabled: bool, - depth_test_enabled: bool, - stencil_test_enabled: bool, - scissor_test_enabled: bool, - #[cfg(feature = "primitive_restart_support")] - primitive_restart_enabled: Option, - #[cfg(feature = "bind_vertex_array_support")] - vertex_array_object: Option, -} - -fn to_native_gl(handle: u32, constructor: fn(NonZeroU32) -> T) -> Option { - if handle != 0 { - Some(constructor(NonZeroU32::new(handle).unwrap())) - } else { - None - } -} - -impl GlStateBackup { - fn pre_init(&mut self, gl: &Context) { - self.texture = unsafe { gl.get_parameter_i32(glow::TEXTURE_BINDING_2D) as _ }; - } - - fn post_init(&mut self, gl: &Context) { - #[allow(clippy::cast_sign_loss)] - unsafe { - gl.bind_texture( - glow::TEXTURE_2D, - to_native_gl(self.texture, glow::NativeTexture), - ); - } - } - - fn pre_render(&mut self, gl: &Context, gl_version: GlVersion) { - #[allow(clippy::cast_sign_loss)] - unsafe { - self.active_texture = gl.get_parameter_i32(glow::ACTIVE_TEXTURE) as _; - self.program = gl.get_parameter_i32(glow::CURRENT_PROGRAM) as _; - self.texture = gl.get_parameter_i32(glow::TEXTURE_BINDING_2D) as _; - #[cfg(feature = "bind_sampler_support")] - if gl_version.bind_sampler_support() { - self.sampler = Some(gl.get_parameter_i32(glow::SAMPLER_BINDING) as _); - } else { - self.sampler = None; - } - self.array_buffer = gl.get_parameter_i32(glow::ARRAY_BUFFER_BINDING) as _; - - #[cfg(feature = "bind_vertex_array_support")] - if gl_version.bind_vertex_array_support() { - self.vertex_array_object = - Some(gl.get_parameter_i32(glow::VERTEX_ARRAY_BINDING) as _); - } - - #[cfg(feature = "polygon_mode_support")] - if gl_version.polygon_mode_support() { - if self.polygon_mode.is_none() { - self.polygon_mode = Some(Default::default()); - } - gl.get_parameter_i32_slice(glow::POLYGON_MODE, self.polygon_mode.as_mut().unwrap()); - } else { - self.polygon_mode = None; - } - gl.get_parameter_i32_slice(glow::VIEWPORT, &mut self.viewport); - gl.get_parameter_i32_slice(glow::SCISSOR_BOX, &mut self.scissor_box); - self.blend_src_rgb = gl.get_parameter_i32(glow::BLEND_SRC_RGB); - self.blend_dst_rgb = gl.get_parameter_i32(glow::BLEND_DST_RGB); - self.blend_src_alpha = gl.get_parameter_i32(glow::BLEND_SRC_ALPHA); - self.blend_dst_alpha = gl.get_parameter_i32(glow::BLEND_DST_ALPHA); - self.blend_equation_rgb = gl.get_parameter_i32(glow::BLEND_EQUATION_RGB); - self.blend_equation_alpha = gl.get_parameter_i32(glow::BLEND_EQUATION_ALPHA); - self.blend_enabled = gl.is_enabled(glow::BLEND); - self.cull_face_enabled = gl.is_enabled(glow::CULL_FACE); - self.depth_test_enabled = gl.is_enabled(glow::DEPTH_TEST); - self.stencil_test_enabled = gl.is_enabled(glow::STENCIL_TEST); - self.scissor_test_enabled = gl.is_enabled(glow::SCISSOR_TEST); - #[cfg(feature = "primitive_restart_support")] - if gl_version.primitive_restart_support() { - self.primitive_restart_enabled = Some(gl.is_enabled(glow::PRIMITIVE_RESTART)); - } else { - self.primitive_restart_enabled = None; - } - } - } - - fn post_render(&mut self, gl: &Context, _gl_version: GlVersion) { - #![allow(clippy::cast_sign_loss)] - unsafe { - gl.use_program(to_native_gl(self.program, glow::NativeProgram)); - gl.bind_texture( - glow::TEXTURE_2D, - to_native_gl(self.texture, glow::NativeTexture), - ); - #[cfg(feature = "bind_sampler_support")] - if let Some(sampler) = self.sampler { - gl.bind_sampler(0, to_native_gl(sampler, glow::NativeSampler)); - } - gl.active_texture(self.active_texture as _); - #[cfg(feature = "bind_vertex_array_support")] - if let Some(vao) = self.vertex_array_object { - gl.bind_vertex_array(to_native_gl(vao, glow::NativeVertexArray)); - } - gl.bind_buffer( - glow::ARRAY_BUFFER, - to_native_gl(self.array_buffer, glow::NativeBuffer), - ); - gl.blend_equation_separate( - self.blend_equation_rgb as _, - self.blend_equation_alpha as _, - ); - gl.blend_func_separate( - self.blend_src_rgb as _, - self.blend_dst_rgb as _, - self.blend_src_alpha as _, - self.blend_dst_alpha as _, - ); - if self.blend_enabled { - gl.enable(glow::BLEND) - } else { - gl.disable(glow::BLEND); - } - if self.cull_face_enabled { - gl.enable(glow::CULL_FACE) - } else { - gl.disable(glow::CULL_FACE) - } - if self.depth_test_enabled { - gl.enable(glow::DEPTH_TEST) - } else { - gl.disable(glow::DEPTH_TEST) - } - if self.stencil_test_enabled { - gl.enable(glow::STENCIL_TEST) - } else { - gl.disable(glow::STENCIL_TEST) - } - if self.scissor_test_enabled { - gl.enable(glow::SCISSOR_TEST) - } else { - gl.disable(glow::SCISSOR_TEST) - } - #[cfg(feature = "primitive_restart_support")] - if let Some(restart_enabled) = self.primitive_restart_enabled { - if restart_enabled { - gl.enable(glow::PRIMITIVE_RESTART) - } else { - gl.disable(glow::PRIMITIVE_RESTART) - } - } - #[cfg(feature = "polygon_mode_support")] - if let Some([mode, _]) = self.polygon_mode { - gl.polygon_mode(glow::FRONT_AND_BACK, mode as _); - } - gl.viewport( - self.viewport[0], - self.viewport[1], - self.viewport[2], - self.viewport[3], - ); - gl.scissor( - self.scissor_box[0], - self.scissor_box[1], - self.scissor_box[2], - self.scissor_box[3], - ); - } - } -} - -/// Parses `GL_VERSION` and `GL_SHADING_LANGUAGE_VERSION` at runtime in order to -/// generate shaders which should work on a wide variety of modern devices -/// (GL >= 3.3 and GLES >= 2.0 are expected to work). -struct Shaders { - program: Option, - texture_uniform_location: GlUniformLocation, - matrix_uniform_location: GlUniformLocation, - position_attribute_index: u32, - uv_attribute_index: u32, - color_attribute_index: u32, -} - -impl Shaders { - fn new(gl: &Context, gl_version: GlVersion, output_srgb: bool) -> Result { - let (vertex_source, fragment_source) = - Self::get_shader_sources(gl, gl_version, output_srgb)?; - - let vertex_shader = - unsafe { gl.create_shader(glow::VERTEX_SHADER) }.map_err(ShaderError::CreateShader)?; - unsafe { - gl.shader_source(vertex_shader, &vertex_source); - gl.compile_shader(vertex_shader); - if !gl.get_shader_compile_status(vertex_shader) { - return Err(ShaderError::CompileShader( - gl.get_shader_info_log(vertex_shader), - )); - } - } - - let fragment_shader = unsafe { gl.create_shader(glow::FRAGMENT_SHADER) } - .map_err(ShaderError::CreateShader)?; - unsafe { - gl.shader_source(fragment_shader, &fragment_source); - gl.compile_shader(fragment_shader); - if !gl.get_shader_compile_status(fragment_shader) { - return Err(ShaderError::CompileShader( - gl.get_shader_info_log(fragment_shader), - )); - } - } - - let program = unsafe { gl.create_program() }.map_err(ShaderError::CreateProgram)?; - unsafe { - gl.attach_shader(program, vertex_shader); - gl.attach_shader(program, fragment_shader); - gl.link_program(program); - - if !gl.get_program_link_status(program) { - return Err(ShaderError::LinkProgram(gl.get_program_info_log(program))); - } - - gl.detach_shader(program, vertex_shader); - gl.detach_shader(program, fragment_shader); - gl.delete_shader(vertex_shader); - gl.delete_shader(fragment_shader); - } - - Ok(unsafe { - Self { - program: Some(program), - texture_uniform_location: gl - .get_uniform_location(program, "tex") - .ok_or_else(|| ShaderError::UniformNotFound("tex".into()))?, - matrix_uniform_location: gl - .get_uniform_location(program, "matrix") - .ok_or_else(|| ShaderError::UniformNotFound("matrix".into()))?, - position_attribute_index: gl - .get_attrib_location(program, "position") - .ok_or_else(|| ShaderError::AttributeNotFound("position".into()))?, - uv_attribute_index: gl - .get_attrib_location(program, "uv") - .ok_or_else(|| ShaderError::AttributeNotFound("uv".into()))?, - color_attribute_index: gl - .get_attrib_location(program, "color") - .ok_or_else(|| ShaderError::AttributeNotFound("color".into()))?, - } - }) - } - - fn get_shader_sources( - gl: &Context, - gl_version: GlVersion, - output_srgb: bool, - ) -> Result<(String, String), ShaderError> { - const VERTEX_BODY: &str = r#" -layout (location = 0) in vec2 position; -layout (location = 1) in vec2 uv; -layout (location = 2) in vec4 color; - -uniform mat4 matrix; -out vec2 fragment_uv; -out vec4 fragment_color; - -// Because imgui only specifies sRGB colors -vec4 srgb_to_linear(vec4 srgb_color) { - // Calcuation as documented by OpenGL - vec3 srgb = srgb_color.rgb; - vec3 selector = ceil(srgb - 0.04045); - vec3 less_than_branch = srgb / 12.92; - vec3 greater_than_branch = pow((srgb + 0.055) / 1.055, vec3(2.4)); - return vec4( - mix(less_than_branch, greater_than_branch, selector), - srgb_color.a - ); -} - -void main() { - fragment_uv = uv; - fragment_color = srgb_to_linear(color); - gl_Position = matrix * vec4(position.xy, 0, 1); -} -"#; - const FRAGMENT_BODY: &str = r#" -in vec2 fragment_uv; -in vec4 fragment_color; - -uniform sampler2D tex; -layout (location = 0) out vec4 out_color; - -vec4 linear_to_srgb(vec4 linear_color) { - vec3 linear = linear_color.rgb; - vec3 selector = ceil(linear - 0.0031308); - vec3 less_than_branch = linear * 12.92; - vec3 greater_than_branch = pow(linear, vec3(1.0/2.4)) * 1.055 - 0.055; - return vec4( - mix(less_than_branch, greater_than_branch, selector), - linear_color.a - ); -} - -void main() { - vec4 linear_color = fragment_color * texture(tex, fragment_uv.st); -#ifdef OUTPUT_SRGB - out_color = linear_to_srgb(linear_color); -#else - out_color = linear_color; -#endif -} -"#; - - let glsl_version = GlslVersion::read(gl); - - // Find the lowest common denominator version - let is_gles = gl_version.is_gles || glsl_version.is_gles; - let (major, minor) = if let std::cmp::Ordering::Less = gl_version - .major - .cmp(&glsl_version.major) - .then(gl_version.minor.cmp(&glsl_version.minor)) - { - (gl_version.major, gl_version.minor) - } else { - (glsl_version.major, glsl_version.minor) - }; - - if is_gles && major < 2 { - return Err(ShaderError::IncompatibleVersion(format!( - "This auto-shader OpenGL version 3.0 or OpenGL ES version 2.0 or higher, found: ES {}.{}", - major, minor - ))); - } - if !is_gles && major < 3 { - return Err(ShaderError::IncompatibleVersion(format!( - "This auto-shader OpenGL version 3.0 or OpenGL ES version 2.0 or higher, found: {}.{}", - major, minor - ))); - } - - let vertex_source = format!( - "#version {version}{es_extras}\n{body}", - version = major * 100 + minor * 10, - es_extras = if is_gles { - " es\nprecision mediump float;" - } else { - "" - }, - body = VERTEX_BODY, - ); - let fragment_source = format!( - "#version {version}{es_extras}{defines}\n{body}", - version = major * 100 + minor * 10, - es_extras = if is_gles { - " es\nprecision mediump float;" - } else { - "" - }, - defines = if output_srgb { - "\n#define OUTPUT_SRGB" - } else { - "" - }, - body = FRAGMENT_BODY, - ); - - Ok((vertex_source, fragment_source)) - } -} - -#[derive(Debug)] -pub enum ShaderError { - IncompatibleVersion(String), - CreateShader(String), - CreateProgram(String), - CompileShader(String), - LinkProgram(String), - UniformNotFound(Cow<'static, str>), - AttributeNotFound(Cow<'static, str>), -} - -impl Error for ShaderError {} - -impl Display for ShaderError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::IncompatibleVersion(msg) => write!( - f, - "Shader not compatible with OpenGL version found in the context: {}", - msg - ), - Self::CreateShader(msg) => write!(f, "Error creating shader object: {}", msg), - Self::CreateProgram(msg) => write!(f, "Error creating program object: {}", msg), - Self::CompileShader(msg) => write!(f, "Error compiling shader: {}", msg), - Self::LinkProgram(msg) => write!(f, "Error linking shader program: {}", msg), - Self::UniformNotFound(uniform_name) => { - write!(f, "Uniform `{}` not found in shader program", uniform_name) - } - Self::AttributeNotFound(attribute_name) => { - write!( - f, - "Attribute `{}` not found in shader program", - attribute_name - ) - } - } - } -} - -#[derive(Debug)] -pub enum InitError { - Shader(ShaderError), - CreateBufferObject(String), - CreateTexture(String), - RegisterTexture, - UserError(String), -} - -impl Error for InitError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - match self { - Self::Shader(error) => Some(error), - _ => None, - } - } -} - -impl Display for InitError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Shader(error) => write!(f, "Shader initialisation error: {}", error), - Self::CreateBufferObject(msg) => write!(f, "Error creating buffer object: {}", msg), - Self::CreateTexture(msg) => write!(f, "Error creating texture object: {}", msg), - Self::RegisterTexture => write!(f, "Error registering texture in texture map"), - Self::UserError(msg) => write!(f, "Initialization error: {}", msg), - } - } -} - -impl From for InitError { - fn from(error: ShaderError) -> Self { - Self::Shader(error) - } -} - -pub type RenderError = String; - -fn prepare_font_atlas( - gl: &Context, - fonts: &mut imgui::FontAtlas, - texture_map: &mut T, -) -> Result { - #![allow(clippy::cast_possible_wrap)] - - let atlas_texture = fonts.build_rgba32_texture(); - - let gl_texture = unsafe { gl.create_texture() }.map_err(InitError::CreateTexture)?; - - unsafe { - gl.bind_texture(glow::TEXTURE_2D, Some(gl_texture)); - gl.tex_parameter_i32( - glow::TEXTURE_2D, - glow::TEXTURE_MIN_FILTER, - glow::LINEAR as _, - ); - gl.tex_parameter_i32( - glow::TEXTURE_2D, - glow::TEXTURE_MAG_FILTER, - glow::LINEAR as _, - ); - gl.tex_image_2d( - glow::TEXTURE_2D, - 0, - glow::SRGB8_ALPHA8 as _, - atlas_texture.width as _, - atlas_texture.height as _, - 0, - glow::RGBA, - glow::UNSIGNED_BYTE, - Some(atlas_texture.data), - ); - } - - fonts.tex_id = texture_map - .register(gl_texture) - .ok_or(InitError::RegisterTexture)?; - - Ok(gl_texture) -} - -// this CFG guard disables apple usage of this function -- apple only has supported up to opengl 3.3 -#[cfg(all(not(target_vendor = "apple"), feature = "debug_message_insert_support"))] -fn gl_debug_message(gl: &G, message: impl AsRef) { - unsafe { - gl.debug_message_insert( - glow::DEBUG_SOURCE_APPLICATION, - glow::DEBUG_TYPE_MARKER, - 0, - glow::DEBUG_SEVERITY_NOTIFICATION, - message, - ) - }; -} - -#[cfg(any(target_vendor = "apple", not(feature = "debug_message_insert_support")))] -fn gl_debug_message(_gl: &G, _message: impl AsRef) {} - -fn calculate_matrix(draw_data: &DrawData, clip_origin_is_lower_left: bool) -> [f32; 16] { - #![allow(clippy::deprecated_cfg_attr)] - - 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]; - - #[cfg(feature = "clip_origin_support")] - let (top, bottom) = if clip_origin_is_lower_left { - (top, bottom) - } else { - (bottom, top) - }; - - #[cfg_attr(rustfmt, rustfmt::skip)] - { - [ - 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, - ] - } -} - -unsafe fn to_byte_slice(slice: &[T]) -> &[u8] { - std::slice::from_raw_parts(slice.as_ptr().cast(), std::mem::size_of_val(slice)) -} - -const fn imgui_index_type_as_gl() -> u32 { - match size_of::() { - 1 => glow::UNSIGNED_BYTE, - 2 => glow::UNSIGNED_SHORT, - _ => glow::UNSIGNED_INT, - } -} diff --git a/imgui-glow-renderer/src/versions.rs b/imgui-glow-renderer/src/versions.rs deleted file mode 100644 index f0daaf8..0000000 --- a/imgui-glow-renderer/src/versions.rs +++ /dev/null @@ -1,188 +0,0 @@ -#![allow(clippy::must_use_candidate)] - -#[derive(PartialEq, Clone, Copy, Eq)] -pub struct GlVersion { - pub major: u16, - pub minor: u16, - pub is_gles: bool, -} - -impl GlVersion { - pub const fn gl(major: u16, minor: u16) -> Self { - Self { - major, - minor, - is_gles: false, - } - } - - pub const fn gles(major: u16, minor: u16) -> Self { - Self { - major, - minor, - is_gles: true, - } - } - - pub fn read(gl: &G) -> Self { - Self::parse(&unsafe { gl.get_parameter_string(glow::VERSION) }) - } - - /// Parse the OpenGL version from the version string queried from the driver - /// via the `GL_VERSION` enum. - /// - /// Version strings are documented to be in the form - /// `.[.][ ]` - /// for full-fat OpenGL, and - /// `OpenGL ES .[.][ ]` - /// for OpenGL ES. - /// - /// Examples based on strings found in the wild: - /// ```rust - /// # use imgui_glow_renderer::versions::GlVersion; - /// let version = GlVersion::parse("4.6.0 NVIDIA 465.27"); - /// assert!(!version.is_gles); - /// assert_eq!(version.major, 4); - /// assert_eq!(version.minor, 6); - /// let version = GlVersion::parse("OpenGL ES 3.2 NVIDIA 465.27"); - /// assert!(version.is_gles); - /// assert_eq!(version.major, 3); - /// assert_eq!(version.minor, 2); - /// ``` - pub fn parse(gl_version_string: &str) -> Self { - let (version_string, is_gles) = gl_version_string - .strip_prefix("OpenGL ES ") - .map_or_else(|| (gl_version_string, false), |version| (version, true)); - - let mut parts = version_string.split(|c: char| !c.is_numeric()); - let major = parts.next().unwrap_or("0").parse().unwrap_or(0); - let minor = parts.next().unwrap_or("0").parse().unwrap_or(0); - - Self { - major, - minor, - is_gles, - } - } - - /// Debug messages are provided by `glDebugMessageInsert`, which is only - /// present in OpenGL >= 4.3 - #[cfg(feature = "debug_message_insert_support")] - pub fn debug_message_insert_support(self) -> bool { - self >= Self::gl(4, 3) - } - - /// Vertex array binding is provided by `glBindVertexArray`, which is - /// not present in OpenGL (ES) <3.0 - #[cfg(feature = "bind_vertex_array_support")] - pub fn bind_vertex_array_support(self) -> bool { - self.major >= 3 - } - - /// Vertex offset support is provided by `glDrawElementsBaseVertex`, which is - /// only present from OpenGL 3.2 and above. - #[cfg(feature = "vertex_offset_support")] - pub fn vertex_offset_support(self) -> bool { - self >= Self::gl(3, 2) - } - - /// Vertex arrays (e.g. `glBindVertexArray`) are supported from OpenGL 3.0 - /// and OpenGL ES 3.0 - #[cfg(feature = "vertex_array_support")] - pub fn vertex_array_support(self) -> bool { - self >= Self::gl(3, 0) || self >= Self::gles(3, 0) - } - - /// Separate binding of sampler (`glBindSampler`) is supported from OpenGL - /// 3.2 or ES 3.0 - #[cfg(feature = "bind_sampler_support")] - pub fn bind_sampler_support(self) -> bool { - self >= GlVersion::gl(3, 2) || self >= GlVersion::gles(3, 0) - } - - /// Setting the clip origin (`GL_CLIP_ORIGIN`) is suppoted from OpenGL 4.5 - #[cfg(feature = "clip_origin_support")] - pub fn clip_origin_support(self) -> bool { - self >= GlVersion::gl(4, 5) - } - - #[cfg(feature = "polygon_mode_support")] - pub fn polygon_mode_support(self) -> bool { - !self.is_gles - } - - #[cfg(feature = "primitive_restart_support")] - pub fn primitive_restart_support(self) -> bool { - self >= GlVersion::gl(3, 1) - } -} - -impl PartialOrd for GlVersion { - fn partial_cmp(&self, other: &Self) -> Option { - if self.is_gles == other.is_gles { - Some( - self.major - .cmp(&other.major) - .then(self.minor.cmp(&other.minor)), - ) - } else { - None - } - } -} - -pub struct GlslVersion { - pub major: u16, - pub minor: u16, - pub is_gles: bool, -} - -impl GlslVersion { - pub fn read(gl: &G) -> Self { - Self::parse(&unsafe { gl.get_parameter_string(glow::SHADING_LANGUAGE_VERSION) }) - } - - /// Parse the OpenGL version from the version string queried from the driver - /// via the `GL_SHADING_LANGUAGE_VERSION` enum. - /// - /// Version strings are documented to be in the form - /// `.[.][ ]` - /// for full-fat OpenGL, and - /// `OpenGL ES GLSL ES .[.][ ]` - /// for OpenGL ES (however, strings omitting that prefix have been observed). - /// - /// Examples based on strings found in the wild: - /// ```rust - /// # use imgui_glow_renderer::versions::GlslVersion; - /// let version = GlslVersion::parse("4.60 NVIDIA"); - /// assert!(!version.is_gles); - /// assert_eq!(version.major, 4); - /// assert_eq!(version.minor, 6); - /// let version = GlslVersion::parse("OpenGL ES GLSL ES 3.20"); - /// assert!(version.is_gles); - /// assert_eq!(version.major, 3); - /// assert_eq!(version.minor, 2); - /// ``` - pub fn parse(gl_shading_language_version: &str) -> Self { - let (version_string, is_gles) = gl_shading_language_version - .strip_prefix("OpenGL ES GLSL ES ") - .map_or_else( - || (gl_shading_language_version, false), - |version| (version, true), - ); - - let mut parts = version_string.split(|c: char| !c.is_numeric()); - let major = parts.next().unwrap_or("0").parse().unwrap_or(0); - let minor = parts.next().unwrap_or("0").parse().unwrap_or(0); - - // The minor version has been observed specified as both a single- or - // double-digit version - let minor = if minor >= 10 { minor / 10 } else { minor }; - - Self { - major, - minor, - is_gles, - } - } -} diff --git a/imgui-sdl2-support/Cargo.toml b/imgui-sdl2-support/Cargo.toml deleted file mode 100644 index 6a9796f..0000000 --- a/imgui-sdl2-support/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "imgui-sdl2-support" -version = "0.12.0" -edition = "2021" -authors = ["The imgui-rs Developers"] -description = "sdl2 support code for the imgui crate" -homepage = "https://github.com/imgui-rs/imgui-rs" -repository = "https://github.com/imgui-rs/imgui-rs" -documentation = "https://docs.rs/imgui-sdl2-support" -license = "MIT OR Apache-2.0" -categories = ["gui"] - -[dependencies] -imgui = { version = "0.12.0", path = "../imgui" } -sdl2 = "0.36" - -[dev-dependencies] -glow = "0.13.1" -imgui-glow-renderer = { version = "0.12.0", path = "../imgui-glow-renderer" } -sdl2 = { version = "0.36", features = ["bundled", "static-link"] } diff --git a/imgui-sdl2-support/LICENSE-APACHE b/imgui-sdl2-support/LICENSE-APACHE deleted file mode 100644 index 3b7a7f9..0000000 --- a/imgui-sdl2-support/LICENSE-APACHE +++ /dev/null @@ -1,202 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2021 the imgui-rs developers - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - diff --git a/imgui-sdl2-support/LICENSE-MIT b/imgui-sdl2-support/LICENSE-MIT deleted file mode 100644 index 230b8c4..0000000 --- a/imgui-sdl2-support/LICENSE-MIT +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2021 The imgui-rs Developers - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/imgui-sdl2-support/examples/sdl2_01_basic.rs b/imgui-sdl2-support/examples/sdl2_01_basic.rs deleted file mode 100644 index f89ea26..0000000 --- a/imgui-sdl2-support/examples/sdl2_01_basic.rs +++ /dev/null @@ -1,92 +0,0 @@ -use glow::HasContext; -use imgui::Context; -use imgui_glow_renderer::AutoRenderer; -use imgui_sdl2_support::SdlPlatform; -use sdl2::{ - event::Event, - video::{GLProfile, Window}, -}; - -// Create a new glow context. -fn glow_context(window: &Window) -> glow::Context { - unsafe { - glow::Context::from_loader_function(|s| window.subsystem().gl_get_proc_address(s) as _) - } -} - -fn main() { - /* initialize SDL and its video subsystem */ - let sdl = sdl2::init().unwrap(); - let video_subsystem = sdl.video().unwrap(); - - /* hint SDL to initialize an OpenGL 3.3 core profile context */ - let gl_attr = video_subsystem.gl_attr(); - - gl_attr.set_context_version(3, 3); - gl_attr.set_context_profile(GLProfile::Core); - - /* create a new window, be sure to call opengl method on the builder when using glow! */ - let window = video_subsystem - .window("Hello imgui-rs!", 1280, 720) - .allow_highdpi() - .opengl() - .position_centered() - .resizable() - .build() - .unwrap(); - - /* create a new OpenGL context and make it current */ - let gl_context = window.gl_create_context().unwrap(); - window.gl_make_current(&gl_context).unwrap(); - - /* enable vsync to cap framerate */ - window.subsystem().gl_set_swap_interval(1).unwrap(); - - /* create new glow and imgui contexts */ - let gl = glow_context(&window); - - /* create context */ - let mut imgui = Context::create(); - - /* disable creation of files on disc */ - imgui.set_ini_filename(None); - imgui.set_log_filename(None); - - /* setup platform and renderer, and fonts to imgui */ - imgui - .fonts() - .add_font(&[imgui::FontSource::DefaultFontData { config: None }]); - - /* create platform and renderer */ - let mut platform = SdlPlatform::init(&mut imgui); - let mut renderer = AutoRenderer::initialize(gl, &mut imgui).unwrap(); - - /* start main loop */ - let mut event_pump = sdl.event_pump().unwrap(); - - 'main: loop { - for event in event_pump.poll_iter() { - /* pass all events to imgui platfrom */ - platform.handle_event(&mut imgui, &event); - - if let Event::Quit { .. } = event { - break 'main; - } - } - - /* call prepare_frame before calling imgui.new_frame() */ - platform.prepare_frame(&mut imgui, &window, &event_pump); - - let ui = imgui.new_frame(); - /* create imgui UI here */ - ui.show_demo_window(&mut true); - - /* render */ - let draw_data = imgui.render(); - - unsafe { renderer.gl_context().clear(glow::COLOR_BUFFER_BIT) }; - renderer.render(draw_data).unwrap(); - - window.gl_swap_window(); - } -} diff --git a/imgui-sdl2-support/src/lib.rs b/imgui-sdl2-support/src/lib.rs deleted file mode 100644 index 562b57c..0000000 --- a/imgui-sdl2-support/src/lib.rs +++ /dev/null @@ -1,388 +0,0 @@ -//! This crate provides a SDL 2 based backend platform for imgui-rs. -//! -//! A backend platform handles window/input device events and manages their -//! state. -//! -//! # Using the library -//! -//! There are three things you need to do to use this library correctly: -//! -//! 1. Initialize a `SdlPlatform` instance -//! 2. Pass events to the platform (every frame) -//! 3. Call frame preparation callback (every frame) -//! -//! For a complete example, take a look at the imgui-rs' GitHub repository. - -use std::time::Instant; - -use imgui::{BackendFlags, ConfigFlags, Context, Io, MouseCursor}; -use sdl2::{ - event::Event, - keyboard::{Mod, Scancode}, - mouse::{Cursor, MouseState, SystemCursor}, - video::Window, - EventPump, -}; - -/// Handle changes in the key states. -fn handle_key(io: &mut Io, key: &Scancode, pressed: bool) { - let igkey = match key { - Scancode::A => imgui::Key::A, - Scancode::B => imgui::Key::B, - Scancode::C => imgui::Key::C, - Scancode::D => imgui::Key::D, - Scancode::E => imgui::Key::E, - Scancode::F => imgui::Key::F, - Scancode::G => imgui::Key::G, - Scancode::H => imgui::Key::H, - Scancode::I => imgui::Key::I, - Scancode::J => imgui::Key::J, - Scancode::K => imgui::Key::K, - Scancode::L => imgui::Key::L, - Scancode::M => imgui::Key::M, - Scancode::N => imgui::Key::N, - Scancode::O => imgui::Key::O, - Scancode::P => imgui::Key::P, - Scancode::Q => imgui::Key::Q, - Scancode::R => imgui::Key::R, - Scancode::S => imgui::Key::S, - Scancode::T => imgui::Key::T, - Scancode::U => imgui::Key::U, - Scancode::V => imgui::Key::V, - Scancode::W => imgui::Key::W, - Scancode::X => imgui::Key::X, - Scancode::Y => imgui::Key::Y, - Scancode::Z => imgui::Key::Z, - Scancode::Num1 => imgui::Key::Keypad1, - Scancode::Num2 => imgui::Key::Keypad2, - Scancode::Num3 => imgui::Key::Keypad3, - Scancode::Num4 => imgui::Key::Keypad4, - Scancode::Num5 => imgui::Key::Keypad5, - Scancode::Num6 => imgui::Key::Keypad6, - Scancode::Num7 => imgui::Key::Keypad7, - Scancode::Num8 => imgui::Key::Keypad8, - Scancode::Num9 => imgui::Key::Keypad9, - Scancode::Num0 => imgui::Key::Keypad0, - Scancode::Return => imgui::Key::Enter, // TODO: Should this be treated as alias? - Scancode::Escape => imgui::Key::Escape, - Scancode::Backspace => imgui::Key::Backspace, - Scancode::Tab => imgui::Key::Tab, - Scancode::Space => imgui::Key::Space, - Scancode::Minus => imgui::Key::Minus, - Scancode::Equals => imgui::Key::Equal, - Scancode::LeftBracket => imgui::Key::LeftBracket, - Scancode::RightBracket => imgui::Key::RightBracket, - Scancode::Backslash => imgui::Key::Backslash, - Scancode::Semicolon => imgui::Key::Semicolon, - Scancode::Apostrophe => imgui::Key::Apostrophe, - Scancode::Grave => imgui::Key::GraveAccent, - Scancode::Comma => imgui::Key::Comma, - Scancode::Period => imgui::Key::Period, - Scancode::Slash => imgui::Key::Slash, - Scancode::CapsLock => imgui::Key::CapsLock, - Scancode::F1 => imgui::Key::F1, - Scancode::F2 => imgui::Key::F2, - Scancode::F3 => imgui::Key::F3, - Scancode::F4 => imgui::Key::F4, - Scancode::F5 => imgui::Key::F5, - Scancode::F6 => imgui::Key::F6, - Scancode::F7 => imgui::Key::F7, - Scancode::F8 => imgui::Key::F8, - Scancode::F9 => imgui::Key::F9, - Scancode::F10 => imgui::Key::F10, - Scancode::F11 => imgui::Key::F11, - Scancode::F12 => imgui::Key::F12, - Scancode::PrintScreen => imgui::Key::PrintScreen, - Scancode::ScrollLock => imgui::Key::ScrollLock, - Scancode::Pause => imgui::Key::Pause, - Scancode::Insert => imgui::Key::Insert, - Scancode::Home => imgui::Key::Home, - Scancode::PageUp => imgui::Key::PageUp, - Scancode::Delete => imgui::Key::Delete, - Scancode::End => imgui::Key::End, - Scancode::PageDown => imgui::Key::PageDown, - Scancode::Right => imgui::Key::RightArrow, - Scancode::Left => imgui::Key::LeftArrow, - Scancode::Down => imgui::Key::DownArrow, - Scancode::Up => imgui::Key::UpArrow, - Scancode::KpDivide => imgui::Key::KeypadDivide, - Scancode::KpMultiply => imgui::Key::KeypadMultiply, - Scancode::KpMinus => imgui::Key::KeypadSubtract, - Scancode::KpPlus => imgui::Key::KeypadAdd, - Scancode::KpEnter => imgui::Key::KeypadEnter, - Scancode::Kp1 => imgui::Key::Keypad1, - Scancode::Kp2 => imgui::Key::Keypad2, - Scancode::Kp3 => imgui::Key::Keypad3, - Scancode::Kp4 => imgui::Key::Keypad4, - Scancode::Kp5 => imgui::Key::Keypad5, - Scancode::Kp6 => imgui::Key::Keypad6, - Scancode::Kp7 => imgui::Key::Keypad7, - Scancode::Kp8 => imgui::Key::Keypad8, - Scancode::Kp9 => imgui::Key::Keypad9, - Scancode::Kp0 => imgui::Key::Keypad0, - Scancode::KpPeriod => imgui::Key::KeypadDecimal, - Scancode::Application => imgui::Key::Menu, - Scancode::KpEquals => imgui::Key::KeypadEqual, - Scancode::Menu => imgui::Key::Menu, - Scancode::LCtrl => imgui::Key::LeftCtrl, - Scancode::LShift => imgui::Key::LeftShift, - Scancode::LAlt => imgui::Key::LeftAlt, - Scancode::LGui => imgui::Key::LeftSuper, - Scancode::RCtrl => imgui::Key::RightCtrl, - Scancode::RShift => imgui::Key::RightShift, - Scancode::RAlt => imgui::Key::RightAlt, - Scancode::RGui => imgui::Key::RightSuper, - _ => { - // Ignore unknown keys - return; - } - }; - - io.add_key_event(igkey, pressed); -} - -/// Handle changes in the key modifier states. -fn handle_key_modifier(io: &mut Io, keymod: &Mod) { - io.add_key_event( - imgui::Key::ModShift, - keymod.intersects(Mod::LSHIFTMOD | Mod::RSHIFTMOD), - ); - io.add_key_event( - imgui::Key::ModCtrl, - keymod.intersects(Mod::LCTRLMOD | Mod::RCTRLMOD), - ); - io.add_key_event( - imgui::Key::ModAlt, - keymod.intersects(Mod::LALTMOD | Mod::RALTMOD), - ); - io.add_key_event( - imgui::Key::ModSuper, - keymod.intersects(Mod::LGUIMOD | Mod::RGUIMOD), - ); -} - -/// Map an imgui::MouseCursor to an equivalent sdl2::mouse::SystemCursor. -fn to_sdl_cursor(cursor: MouseCursor) -> SystemCursor { - match cursor { - MouseCursor::Arrow => SystemCursor::Arrow, - MouseCursor::TextInput => SystemCursor::IBeam, - MouseCursor::ResizeAll => SystemCursor::SizeAll, - MouseCursor::ResizeNS => SystemCursor::SizeNS, - MouseCursor::ResizeEW => SystemCursor::SizeWE, - MouseCursor::ResizeNESW => SystemCursor::SizeNESW, - MouseCursor::ResizeNWSE => SystemCursor::SizeNWSE, - MouseCursor::Hand => SystemCursor::Hand, - MouseCursor::NotAllowed => SystemCursor::No, - } -} - -/// Returns `true` if the provided event is associated with the provided window. -/// -/// # Example -/// ```rust,no_run -/// # let mut event_pump: sdl2::EventPump = unimplemented!(); -/// # let window: sdl2::video::Window = unimplemented!(); -/// # let mut imgui = imgui::Context::create(); -/// # let mut platform = SdlPlatform::init(&mut imgui); -/// use imgui_sdl2_support::{SdlPlatform, filter_event}; -/// // Assuming there are multiple windows, we only want to provide the events -/// // of the window where we are rendering to imgui-rs -/// for event in event_pump.poll_iter().filter(|event| filter_event(&window, event)) { -/// platform.handle_event(&mut imgui, &event); -/// } -/// ``` -pub fn filter_event(window: &Window, event: &Event) -> bool { - Some(window.id()) == event.get_window_id() -} - -/// SDL 2 backend platform state. -/// -/// A backend platform handles window/input device events and manages their -/// state. -/// -/// There are three things you need to do to use this library correctly: -/// -/// 1. Initialize a `SdlPlatform` instance -/// 2. Pass events to the platform (every frame) -/// 3. Call frame preparation callback (every frame) -pub struct SdlPlatform { - cursor_instance: Option, /* to avoid dropping cursor instances */ - last_frame: Instant, -} - -impl SdlPlatform { - /// Initializes a SDL platform instance and configures imgui. - /// - /// This function configures imgui-rs in the following ways: - /// - /// * backend flags are updated - /// * keys are configured - /// * platform name is set - pub fn init(imgui: &mut Context) -> SdlPlatform { - let io = imgui.io_mut(); - - io.backend_flags.insert(BackendFlags::HAS_MOUSE_CURSORS); - io.backend_flags.insert(BackendFlags::HAS_SET_MOUSE_POS); - - imgui.set_platform_name(Some(format!( - "imgui-sdl2-support {}", - env!("CARGO_PKG_VERSION") - ))); - - SdlPlatform { - cursor_instance: None, - last_frame: Instant::now(), - } - } - - /// Handles a SDL event. - /// - /// This function performs the following actions (depends on the event): - /// - /// * keyboard state is updated - /// * mouse state is updated - pub fn handle_event(&mut self, context: &mut Context, event: &Event) -> bool { - let io = context.io_mut(); - - match *event { - Event::MouseWheel { x, y, .. } => { - io.add_mouse_wheel_event([x as f32, y as f32]); - true - } - - Event::MouseButtonDown { mouse_btn, .. } => { - self.handle_mouse_button(io, &mouse_btn, true); - true - } - - Event::MouseButtonUp { mouse_btn, .. } => { - self.handle_mouse_button(io, &mouse_btn, false); - true - } - - Event::TextInput { ref text, .. } => { - text.chars().for_each(|c| io.add_input_character(c)); - true - } - - Event::KeyDown { - scancode: Some(key), - keymod, - .. - } => { - handle_key_modifier(io, &keymod); - handle_key(io, &key, true); - true - } - - Event::KeyUp { - scancode: Some(key), - keymod, - .. - } => { - handle_key_modifier(io, &keymod); - handle_key(io, &key, false); - true - } - - _ => false, - } - } - - /// Frame preparation callback. - /// - /// Call this before calling the imgui-rs context `frame` function. - /// This function performs the following actions: - /// - /// * display size and the framebuffer scale is set - /// * mouse cursor is repositioned (if requested by imgui-rs) - /// * current mouse cursor position is passed to imgui-rs - /// * changes mouse cursor icon (if requested by imgui-rs) - pub fn prepare_frame( - &mut self, - context: &mut Context, - window: &Window, - event_pump: &EventPump, - ) { - let mouse_cursor = context.mouse_cursor(); - let io = context.io_mut(); - - // Update delta time - let now = Instant::now(); - io.update_delta_time(now.duration_since(self.last_frame)); - self.last_frame = now; - - let mouse_state = MouseState::new(event_pump); - let window_size = window.size(); - let window_drawable_size = window.drawable_size(); - - // Set display size and scale here, since SDL 2 doesn't have - // any easy way to get the scale factor, and changes in said - // scale factor - io.display_size = [window_size.0 as f32, window_size.1 as f32]; - io.display_framebuffer_scale = [ - (window_drawable_size.0 as f32) / (window_size.0 as f32), - (window_drawable_size.1 as f32) / (window_size.1 as f32), - ]; - - // Set mouse position if requested by imgui-rs - if io.want_set_mouse_pos { - let mouse_util = window.subsystem().sdl().mouse(); - mouse_util.warp_mouse_in_window(window, io.mouse_pos[0] as i32, io.mouse_pos[1] as i32); - } - - // Update mouse cursor position - io.mouse_pos = [mouse_state.x() as f32, mouse_state.y() as f32]; - - // Update mouse cursor icon if requested - if !io - .config_flags - .contains(ConfigFlags::NO_MOUSE_CURSOR_CHANGE) - { - let mouse_util = window.subsystem().sdl().mouse(); - - match mouse_cursor { - Some(mouse_cursor) if !io.mouse_draw_cursor => { - let cursor = Cursor::from_system(to_sdl_cursor(mouse_cursor)).unwrap(); - cursor.set(); - - mouse_util.show_cursor(true); - self.cursor_instance = Some(cursor); - } - - _ => { - mouse_util.show_cursor(false); - self.cursor_instance = None; - } - } - } - } -} - -impl SdlPlatform { - fn handle_mouse_button( - &mut self, - io: &mut Io, - button: &sdl2::mouse::MouseButton, - pressed: bool, - ) { - match button { - sdl2::mouse::MouseButton::Left => { - io.add_mouse_button_event(imgui::MouseButton::Left, pressed) - } - sdl2::mouse::MouseButton::Right => { - io.add_mouse_button_event(imgui::MouseButton::Right, pressed) - } - sdl2::mouse::MouseButton::Middle => { - io.add_mouse_button_event(imgui::MouseButton::Middle, pressed) - } - sdl2::mouse::MouseButton::X1 => { - io.add_mouse_button_event(imgui::MouseButton::Extra1, pressed) - } - sdl2::mouse::MouseButton::X2 => { - io.add_mouse_button_event(imgui::MouseButton::Extra2, pressed) - } - _ => {} - } - } -} diff --git a/imgui-winit-glow-renderer-viewports/Cargo.toml b/imgui-winit-glow-renderer-viewports/Cargo.toml deleted file mode 100644 index f203252..0000000 --- a/imgui-winit-glow-renderer-viewports/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "imgui-winit-glow-renderer-viewports" -version = "0.12.0" -edition = "2021" -description = "combined platform + renderer using the docking branch viewport feature" -homepage = "https://github.com/imgui-rs/imgui-rs" -repository = "https://github.com/imgui-rs/imgui-rs" -license = "MIT OR Apache-2.0" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -imgui = { version = "0.12.0", path="../imgui", features=["docking"] } - -glow = "0.13.1" -glutin = "0.31.1" -glutin-winit = "0.4.2" -raw-window-handle = "0.5.0" -winit = "0.29.3" -thiserror = "1.0.38" diff --git a/imgui-winit-glow-renderer-viewports/examples/viewports_basic.rs b/imgui-winit-glow-renderer-viewports/examples/viewports_basic.rs deleted file mode 100644 index 1328346..0000000 --- a/imgui-winit-glow-renderer-viewports/examples/viewports_basic.rs +++ /dev/null @@ -1,170 +0,0 @@ -use std::{ffi::CString, num::NonZeroU32, time::Instant}; - -use glow::{Context, HasContext}; -use glutin::{ - config::ConfigTemplateBuilder, - context::{ContextAttributesBuilder, NotCurrentGlContext, PossiblyCurrentGlContext}, - display::GetGlDisplay, - prelude::GlDisplay, - 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::WindowEvent, - event_loop::{ControlFlow, EventLoop}, - window::WindowBuilder, -}; - -fn main() { - let event_loop = EventLoop::new().expect("Failed to create EventLoop"); - - 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); - 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| { - window_target.set_control_flow(ControlFlow::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() => { - window_target.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::AboutToWait => { - window.request_redraw(); - } - winit::event::Event::WindowEvent { - event: WindowEvent::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(); - - renderer.prepare_render(&mut imgui, &window); - - imgui.update_platform_windows(); - renderer - .update_viewports(&mut imgui, window_target, &glow) - .expect("Failed to update viewports"); - - let draw_data = imgui.render(); - - 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); - } - - 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"); - } - _ => {} - } - }) - .expect("EventLoop error"); -} diff --git a/imgui-winit-glow-renderer-viewports/src/fragment_shader.glsl b/imgui-winit-glow-renderer-viewports/src/fragment_shader.glsl deleted file mode 100644 index 505432c..0000000 --- a/imgui-winit-glow-renderer-viewports/src/fragment_shader.glsl +++ /dev/null @@ -1,13 +0,0 @@ -#version 330 - -in vec2 v2f_UV; -in vec4 v2f_Color; - -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 deleted file mode 100644 index 22b2c5b..0000000 --- a/imgui-winit-glow-renderer-viewports/src/lib.rs +++ /dev/null @@ -1,1144 +0,0 @@ -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, NotCurrentGlContext, PossiblyCurrentGlContext, - }, - display::GetGlDisplay, - prelude::GlDisplay, - surface::{GlSurface, Surface, SurfaceAttributesBuilder, WindowSurface}, -}; -use glutin_winit::DisplayBuilder; -use imgui::{BackendFlags, ConfigFlags, Id, Io, Key, MouseButton, ViewportFlags}; -use raw_window_handle::{HasRawWindowHandle, RawWindowHandle}; -use thiserror::Error; -use winit::{ - dpi::{PhysicalPosition, PhysicalSize}, - event::{ElementState, TouchPhase}, - event_loop::EventLoopWindowTarget, - keyboard::{Key as WinitKey, KeyLocation, NamedKey}, - platform::modifier_supplement::KeyEventExtModifierSupplement, - window::{CursorIcon, 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 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)] -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, - /// 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, - ( - GlObjects, - Surface, - Option, - Window, - ), - >, - event_queue: Rc>>, - font_width: u32, - font_height: u32, - font_pixels: Vec, - last_cursor: CursorIcon, -} - -#[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(RendererError::GlShaderCreationFailed)?; - 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(RendererError::GlShaderCreationFailed)?; - 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(RendererError::GlProgramCreationFailed)?; - 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(RendererError::GlTextureCreationFailed)?; - 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 vbo = unsafe { - glow.create_buffer() - .map_err(RendererError::GlBufferCreationFailed)? - }; - let ibo = unsafe { - glow.create_buffer() - .map_err(RendererError::GlBufferCreationFailed)? - }; - - let vao = unsafe { - let vao = glow - .create_vertex_array() - .map_err(RendererError::GlVertexArrayCreationFailed)?; - - 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, - vao, - vbo, - ibo, - }) - } -} - -#[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: u32, - vbo: u32, - ibo: u32, - active_texture: u32, - texture: u32, - program: u32, -} - -fn to_native_gl(handle: u32, constructor: fn(NonZeroU32) -> T) -> Option { - if handle != 0 { - Some(constructor(NonZeroU32::new(handle).unwrap())) - } else { - None - } -} - -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) as _; - let vbo = context.get_parameter_i32(glow::ARRAY_BUFFER_BINDING) as _; - let ibo = context.get_parameter_i32(glow::ELEMENT_ARRAY_BUFFER_BINDING) as _; - - let active_texture = context.get_parameter_i32(glow::ACTIVE_TEXTURE) as _; - context.active_texture(0); - let texture = context.get_parameter_i32(glow::TEXTURE_BINDING_2D) as _; - - let program = context.get_parameter_i32(glow::CURRENT_PROGRAM) as _; - - 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], - ); - - context.bind_vertex_array(to_native_gl(self.vao, glow::NativeVertexArray)); - - context.bind_buffer( - glow::ARRAY_BUFFER, - to_native_gl(self.vbo, glow::NativeBuffer), - ); - context.bind_buffer( - glow::ELEMENT_ARRAY_BUFFER, - to_native_gl(self.ibo, glow::NativeBuffer), - ); - - context.bind_texture( - glow::TEXTURE_2D, - to_native_gl(self.texture, glow::NativeTexture), - ); - context.active_texture(self.active_texture); - - context.use_program(to_native_gl(self.program, glow::NativeProgram)); - } - } - - 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, - main_window: &Window, - gl_context: &glow::Context, - ) -> 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::RENDERER_HAS_VTX_OFFSET); - - 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_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(); - - 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, - font_width: font_tex.width, - font_height: font_tex.height, - font_pixels: font_tex.data.to_vec(), - last_cursor: CursorIcon::Default, - }) - } - - pub fn handle_event( - &mut self, - imgui: &mut imgui::Context, - main_window: &Window, - event: &winit::event::Event, - ) { - if let winit::event::Event::WindowEvent { - window_id, - ref event, - } = *event - { - 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 { - return; - } - } else { - return; - }; - - match *event { - winit::event::WindowEvent::Resized(new_size) => { - unsafe { - (*(viewport.platform_user_data.cast::())).size = - [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]; - } - } - winit::event::WindowEvent::Moved(_) => unsafe { - let new_pos = window.inner_position().unwrap().cast::(); - (*(viewport.platform_user_data.cast::())).pos = - [new_pos.x, new_pos.y]; - - viewport.platform_request_move = true; - }, - winit::event::WindowEvent::CloseRequested if window_id != main_window.id() => { - viewport.platform_request_close = true; - } - winit::event::WindowEvent::Focused(f) => unsafe { - (*(viewport.platform_user_data.cast::())).focus = f; - }, - winit::event::WindowEvent::KeyboardInput { ref event, .. } => { - if let Some(txt) = &event.text { - for ch in txt.chars() { - imgui.io_mut().add_input_character(ch); - } - } - - let key = event.key_without_modifiers(); - - let pressed = event.state == ElementState::Pressed; - - // We map both left and right ctrl to `ModCtrl`, etc. - // imgui is told both "left control is pressed" and - // "consider the control key is pressed". Allows - // applications to use either general "ctrl" or a - // specific key. Same applies to other modifiers. - // https://github.com/ocornut/imgui/issues/5047 - handle_key_modifier(imgui.io_mut(), &key, pressed); - - // Add main key event - if let Some(key) = to_imgui_key(key, event.location) { - imgui.io_mut().add_key_event(key, pressed); - } - } - winit::event::WindowEvent::ModifiersChanged(modifiers) => { - let state = modifiers.state(); - - imgui - .io_mut() - .add_key_event(Key::ModShift, state.shift_key()); - imgui - .io_mut() - .add_key_event(Key::ModCtrl, state.control_key()); - imgui.io_mut().add_key_event(Key::ModAlt, state.alt_key()); - imgui - .io_mut() - .add_key_event(Key::ModSuper, state.super_key()); - } - winit::event::WindowEvent::CursorMoved { position, .. } => { - if imgui - .io() - .config_flags - .contains(ConfigFlags::VIEWPORTS_ENABLE) - { - let window_pos = window.inner_position().unwrap_or_default().cast::(); - 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() - .add_mouse_pos_event([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().add_mouse_wheel_event([h, v]); - } - winit::event::MouseScrollDelta::PixelDelta(pos) => { - let h = if pos.x > 0.0 { - 1.0 - } else if pos.x < 0.0 { - -1.0 - } else { - 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; - - if let Some(button) = to_imgui_mouse_button(button) { - imgui.io_mut().add_mouse_button_event(button, state); - } - } - _ => {} - } - } - } - - 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.request_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 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::Grab, - 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.values() { - wnd.set_cursor_icon(cursor); - } - - self.last_cursor = cursor; - } - } - } - - fn create_extra_window( - &mut self, - viewport: &mut imgui::Viewport, - window_target: &EventLoopWindowTarget, - glow: &glow::Context, - ) -> Result< - ( - GlObjects, - Surface, - Option, - Window, - ), - 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::WindowCreationFailed)? - } 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::WindowCreationFailed)?; - - 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::WindowContextCreationFailed)? - }; - - 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::WindowSurfaceCreationFailed)? - }; - - let context = context - .make_current(&surface) - .map_err(|_| RendererError::MakeCurrentFailed)?; - - let gl_objects = - GlObjects::new(self.font_width, self.font_height, &self.font_pixels, glow)?; - - Ok(( - gl_objects, - surface, - Some(context.make_not_current().unwrap()), - window, - )) - } - - pub fn render( - &mut self, - main_window: &Window, - glow: &glow::Context, - draw_data: &imgui::DrawData, - ) -> Result<(), RendererError> { - 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( - &mut self, - glow: &glow::Context, - imgui: &mut imgui::Context, - ) -> Result<(), RendererError> { - 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() - .unwrap() - .make_current(surface) - .map_err(|_| RendererError::MakeCurrentFailed)?; - - 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::SwapBuffersFailed)?; - - *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.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)); - 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() { - 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, - ); - } - } - } - } - - Ok(()) - } -} - -struct ViewportData { - pos: [f32; 2], - size: [f32; 2], - focus: bool, - minimized: bool, -} - -struct PlatformBackend { - event_queue: Rc>>, -} - -fn handle_key_modifier(io: &mut Io, key: &WinitKey, down: bool) { - match key { - WinitKey::Named(NamedKey::Shift) => io.add_key_event(imgui::Key::ModShift, down), - WinitKey::Named(NamedKey::Control) => io.add_key_event(imgui::Key::ModCtrl, down), - WinitKey::Named(NamedKey::Alt) => io.add_key_event(imgui::Key::ModAlt, down), - WinitKey::Named(NamedKey::Super) => io.add_key_event(imgui::Key::ModSuper, down), - _ => {} - } -} - -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) {} -} - -fn to_imgui_key(key: winit::keyboard::Key, location: KeyLocation) -> Option { - match (key.as_ref(), location) { - (WinitKey::Named(NamedKey::Tab), _) => Some(Key::Tab), - (WinitKey::Named(NamedKey::ArrowLeft), _) => Some(Key::LeftArrow), - (WinitKey::Named(NamedKey::ArrowRight), _) => Some(Key::RightArrow), - (WinitKey::Named(NamedKey::ArrowUp), _) => Some(Key::UpArrow), - (WinitKey::Named(NamedKey::ArrowDown), _) => Some(Key::DownArrow), - (WinitKey::Named(NamedKey::PageUp), _) => Some(Key::PageUp), - (WinitKey::Named(NamedKey::PageDown), _) => Some(Key::PageDown), - (WinitKey::Named(NamedKey::Home), _) => Some(Key::Home), - (WinitKey::Named(NamedKey::End), _) => Some(Key::End), - (WinitKey::Named(NamedKey::Insert), _) => Some(Key::Insert), - (WinitKey::Named(NamedKey::Delete), _) => Some(Key::Delete), - (WinitKey::Named(NamedKey::Backspace), _) => Some(Key::Backspace), - (WinitKey::Named(NamedKey::Space), _) => Some(Key::Space), - (WinitKey::Named(NamedKey::Enter), KeyLocation::Standard) => Some(Key::Enter), - (WinitKey::Named(NamedKey::Enter), KeyLocation::Numpad) => Some(Key::KeypadEnter), - (WinitKey::Named(NamedKey::Escape), _) => Some(Key::Escape), - (WinitKey::Named(NamedKey::Control), KeyLocation::Left) => Some(Key::LeftCtrl), - (WinitKey::Named(NamedKey::Control), KeyLocation::Right) => Some(Key::RightCtrl), - (WinitKey::Named(NamedKey::Shift), KeyLocation::Left) => Some(Key::LeftShift), - (WinitKey::Named(NamedKey::Shift), KeyLocation::Right) => Some(Key::RightShift), - (WinitKey::Named(NamedKey::Alt), KeyLocation::Left) => Some(Key::LeftAlt), - (WinitKey::Named(NamedKey::Alt), KeyLocation::Right) => Some(Key::RightAlt), - (WinitKey::Named(NamedKey::Super), KeyLocation::Left) => Some(Key::LeftSuper), - (WinitKey::Named(NamedKey::Super), KeyLocation::Right) => Some(Key::RightSuper), - (WinitKey::Named(NamedKey::ContextMenu), _) => Some(Key::Menu), - (WinitKey::Named(NamedKey::F1), _) => Some(Key::F1), - (WinitKey::Named(NamedKey::F2), _) => Some(Key::F2), - (WinitKey::Named(NamedKey::F3), _) => Some(Key::F3), - (WinitKey::Named(NamedKey::F4), _) => Some(Key::F4), - (WinitKey::Named(NamedKey::F5), _) => Some(Key::F5), - (WinitKey::Named(NamedKey::F6), _) => Some(Key::F6), - (WinitKey::Named(NamedKey::F7), _) => Some(Key::F7), - (WinitKey::Named(NamedKey::F8), _) => Some(Key::F8), - (WinitKey::Named(NamedKey::F9), _) => Some(Key::F9), - (WinitKey::Named(NamedKey::F10), _) => Some(Key::F10), - (WinitKey::Named(NamedKey::F11), _) => Some(Key::F11), - (WinitKey::Named(NamedKey::F12), _) => Some(Key::F12), - (WinitKey::Named(NamedKey::CapsLock), _) => Some(Key::CapsLock), - (WinitKey::Named(NamedKey::ScrollLock), _) => Some(Key::ScrollLock), - (WinitKey::Named(NamedKey::NumLock), _) => Some(Key::NumLock), - (WinitKey::Named(NamedKey::PrintScreen), _) => Some(Key::PrintScreen), - (WinitKey::Named(NamedKey::Pause), _) => Some(Key::Pause), - (WinitKey::Character("0"), KeyLocation::Standard) => Some(Key::Alpha0), - (WinitKey::Character("1"), KeyLocation::Standard) => Some(Key::Alpha1), - (WinitKey::Character("2"), KeyLocation::Standard) => Some(Key::Alpha2), - (WinitKey::Character("3"), KeyLocation::Standard) => Some(Key::Alpha3), - (WinitKey::Character("4"), KeyLocation::Standard) => Some(Key::Alpha4), - (WinitKey::Character("5"), KeyLocation::Standard) => Some(Key::Alpha5), - (WinitKey::Character("6"), KeyLocation::Standard) => Some(Key::Alpha6), - (WinitKey::Character("7"), KeyLocation::Standard) => Some(Key::Alpha7), - (WinitKey::Character("8"), KeyLocation::Standard) => Some(Key::Alpha8), - (WinitKey::Character("9"), KeyLocation::Standard) => Some(Key::Alpha9), - (WinitKey::Character("0"), KeyLocation::Numpad) => Some(Key::Keypad0), - (WinitKey::Character("1"), KeyLocation::Numpad) => Some(Key::Keypad1), - (WinitKey::Character("2"), KeyLocation::Numpad) => Some(Key::Keypad2), - (WinitKey::Character("3"), KeyLocation::Numpad) => Some(Key::Keypad3), - (WinitKey::Character("4"), KeyLocation::Numpad) => Some(Key::Keypad4), - (WinitKey::Character("5"), KeyLocation::Numpad) => Some(Key::Keypad5), - (WinitKey::Character("6"), KeyLocation::Numpad) => Some(Key::Keypad6), - (WinitKey::Character("7"), KeyLocation::Numpad) => Some(Key::Keypad7), - (WinitKey::Character("8"), KeyLocation::Numpad) => Some(Key::Keypad8), - (WinitKey::Character("9"), KeyLocation::Numpad) => Some(Key::Keypad9), - (WinitKey::Character("a"), _) => Some(Key::A), - (WinitKey::Character("b"), _) => Some(Key::B), - (WinitKey::Character("c"), _) => Some(Key::C), - (WinitKey::Character("d"), _) => Some(Key::D), - (WinitKey::Character("e"), _) => Some(Key::E), - (WinitKey::Character("f"), _) => Some(Key::F), - (WinitKey::Character("g"), _) => Some(Key::G), - (WinitKey::Character("h"), _) => Some(Key::H), - (WinitKey::Character("i"), _) => Some(Key::I), - (WinitKey::Character("j"), _) => Some(Key::J), - (WinitKey::Character("k"), _) => Some(Key::K), - (WinitKey::Character("l"), _) => Some(Key::L), - (WinitKey::Character("m"), _) => Some(Key::M), - (WinitKey::Character("n"), _) => Some(Key::N), - (WinitKey::Character("o"), _) => Some(Key::O), - (WinitKey::Character("p"), _) => Some(Key::P), - (WinitKey::Character("q"), _) => Some(Key::Q), - (WinitKey::Character("r"), _) => Some(Key::R), - (WinitKey::Character("s"), _) => Some(Key::S), - (WinitKey::Character("t"), _) => Some(Key::T), - (WinitKey::Character("u"), _) => Some(Key::U), - (WinitKey::Character("v"), _) => Some(Key::V), - (WinitKey::Character("w"), _) => Some(Key::W), - (WinitKey::Character("x"), _) => Some(Key::X), - (WinitKey::Character("y"), _) => Some(Key::Y), - (WinitKey::Character("z"), _) => Some(Key::Z), - (WinitKey::Character("'"), _) => Some(Key::Apostrophe), - (WinitKey::Character(","), KeyLocation::Standard) => Some(Key::Comma), - (WinitKey::Character("-"), KeyLocation::Standard) => Some(Key::Minus), - (WinitKey::Character("-"), KeyLocation::Numpad) => Some(Key::KeypadSubtract), - (WinitKey::Character("."), KeyLocation::Standard) => Some(Key::Period), - (WinitKey::Character("."), KeyLocation::Numpad) => Some(Key::KeypadDecimal), - (WinitKey::Character("/"), KeyLocation::Standard) => Some(Key::Slash), - (WinitKey::Character("/"), KeyLocation::Numpad) => Some(Key::KeypadDivide), - (WinitKey::Character(";"), _) => Some(Key::Semicolon), - (WinitKey::Character("="), KeyLocation::Standard) => Some(Key::Equal), - (WinitKey::Character("="), KeyLocation::Numpad) => Some(Key::KeypadEqual), - (WinitKey::Character("["), _) => Some(Key::LeftBracket), - (WinitKey::Character("\\"), _) => Some(Key::Backslash), - (WinitKey::Character("]"), _) => Some(Key::RightBracket), - (WinitKey::Character("`"), _) => Some(Key::GraveAccent), - (WinitKey::Character("*"), KeyLocation::Numpad) => Some(Key::KeypadMultiply), - (WinitKey::Character("+"), KeyLocation::Numpad) => Some(Key::KeypadAdd), - _ => 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, - } -} diff --git a/imgui-winit-glow-renderer-viewports/src/vertex_shader.glsl b/imgui-winit-glow-renderer-viewports/src/vertex_shader.glsl deleted file mode 100644 index 058c47b..0000000 --- a/imgui-winit-glow-renderer-viewports/src/vertex_shader.glsl +++ /dev/null @@ -1,16 +0,0 @@ -#version 330 - -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; -} diff --git a/imgui-winit-support/Cargo.toml b/imgui-winit-support/Cargo.toml deleted file mode 100644 index 59ee88c..0000000 --- a/imgui-winit-support/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "imgui-winit-support" -version = "0.12.0" -edition = "2021" -description = "winit support code for the imgui crate" -homepage = "https://github.com/imgui-rs/imgui-rs" -repository = "https://github.com/imgui-rs/imgui-rs" -documentation = "https://docs.rs/imgui-winit-support" -license = "MIT OR Apache-2.0" -categories = ["gui"] - -[dependencies] -imgui = { version = "0.12.0", path = "../imgui" } -winit = { version = "0.29.3", default-features = false } diff --git a/imgui-winit-support/LICENSE-APACHE b/imgui-winit-support/LICENSE-APACHE deleted file mode 100644 index 3b7a7f9..0000000 --- a/imgui-winit-support/LICENSE-APACHE +++ /dev/null @@ -1,202 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2021 the imgui-rs developers - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - diff --git a/imgui-winit-support/LICENSE-MIT b/imgui-winit-support/LICENSE-MIT deleted file mode 100644 index 230b8c4..0000000 --- a/imgui-winit-support/LICENSE-MIT +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2021 The imgui-rs Developers - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/imgui-winit-support/examples/README.md b/imgui-winit-support/examples/README.md deleted file mode 100644 index 82b9a95..0000000 --- a/imgui-winit-support/examples/README.md +++ /dev/null @@ -1,5 +0,0 @@ -See the examples for [`imgui-glium-renderer`][glium] or [`imgui-glow-renderer`][glow] -for simple examples of this platform backend with different renderers - -[glium]: ../../imgui-glium-renderer/examples -[glow]: ../../imgui-glow-renderer/examples diff --git a/imgui-winit-support/src/lib.rs b/imgui-winit-support/src/lib.rs deleted file mode 100644 index ddc1c8e..0000000 --- a/imgui-winit-support/src/lib.rs +++ /dev/null @@ -1,576 +0,0 @@ -//! This crate provides a winit-based backend platform for imgui-rs. -//! -//! A backend platform handles window/input device events and manages their -//! state. -//! -//! # Using the library -//! -//! There are five things you need to do to use this library correctly: -//! -//! 1. Initialize a `WinitPlatform` instance -//! 2. Attach it to a winit `Window` -//! 3. Pass events to the platform (every frame) -//! 4. Call frame preparation callback (every frame) -//! 5. Call render preparation callback (every frame) -//! -//! ## Complete example (without a renderer) -//! -//! ```no_run -//! use imgui::Context; -//! use imgui_winit_support::{HiDpiMode, WinitPlatform}; -//! use std::time::Instant; -//! use winit::event::{Event, WindowEvent}; -//! use winit::event_loop::{ControlFlow, EventLoop}; -//! use winit::window::Window; -//! -//! let mut event_loop = EventLoop::new().expect("Failed to create EventLoop"); -//! let mut window = Window::new(&event_loop).unwrap(); -//! -//! let mut imgui = Context::create(); -//! // configure imgui-rs Context if necessary -//! -//! let mut platform = WinitPlatform::init(&mut imgui); // step 1 -//! platform.attach_window(imgui.io_mut(), &window, HiDpiMode::Default); // step 2 -//! -//! let mut last_frame = Instant::now(); -//! let mut run = true; -//! event_loop.run(move |event, window_target| { -//! match event { -//! Event::NewEvents(_) => { -//! // other application-specific logic -//! let now = Instant::now(); -//! imgui.io_mut().update_delta_time(now - last_frame); -//! last_frame = now; -//! }, -//! Event::AboutToWait => { -//! // other application-specific logic -//! platform.prepare_frame(imgui.io_mut(), &window) // step 4 -//! .expect("Failed to prepare frame"); -//! window.request_redraw(); -//! } -//! Event::WindowEvent { event: WindowEvent::RedrawRequested, .. } => { -//! let ui = imgui.frame(); -//! // application-specific rendering *under the UI* -//! -//! // construct the UI -//! -//! platform.prepare_render(&ui, &window); // step 5 -//! // render the UI with a renderer -//! let draw_data = imgui.render(); -//! // renderer.render(..., draw_data).expect("UI rendering failed"); -//! -//! // application-specific rendering *over the UI* -//! }, -//! Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => { -//! window_target.exit(); -//! } -//! // other application-specific event handling -//! event => { -//! platform.handle_event(imgui.io_mut(), &window, &event); // step 3 -//! // other application-specific event handling -//! } -//! } -//! }).expect("EventLoop error"); -//! ``` - -use imgui::{self, BackendFlags, ConfigFlags, Context, Io, Key, Ui}; -use std::cmp::Ordering; - -// Re-export winit to make it easier for users to use the correct version. -pub use winit; -use winit::{ - dpi::{LogicalPosition, LogicalSize}, - keyboard::{Key as WinitKey, KeyLocation, NamedKey}, - platform::modifier_supplement::KeyEventExtModifierSupplement, -}; - -use winit::{ - error::ExternalError, - event::{ElementState, Event, MouseButton, MouseScrollDelta, TouchPhase, WindowEvent}, - window::{CursorIcon as MouseCursor, Window}, -}; - -/// winit backend platform state -#[derive(Debug)] -pub struct WinitPlatform { - hidpi_mode: ActiveHiDpiMode, - hidpi_factor: f64, - cursor_cache: Option, -} - -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -struct CursorSettings { - cursor: Option, - draw_cursor: bool, -} - -fn to_winit_cursor(cursor: imgui::MouseCursor) -> MouseCursor { - match cursor { - imgui::MouseCursor::Arrow => MouseCursor::Default, - imgui::MouseCursor::TextInput => MouseCursor::Text, - imgui::MouseCursor::ResizeAll => MouseCursor::Move, - imgui::MouseCursor::ResizeNS => MouseCursor::NsResize, - imgui::MouseCursor::ResizeEW => MouseCursor::EwResize, - imgui::MouseCursor::ResizeNESW => MouseCursor::NeswResize, - imgui::MouseCursor::ResizeNWSE => MouseCursor::NwseResize, - imgui::MouseCursor::Hand => MouseCursor::Grab, - imgui::MouseCursor::NotAllowed => MouseCursor::NotAllowed, - } -} - -impl CursorSettings { - fn apply(&self, window: &Window) { - match self.cursor { - Some(mouse_cursor) if !self.draw_cursor => { - window.set_cursor_visible(true); - window.set_cursor_icon(to_winit_cursor(mouse_cursor)); - } - _ => window.set_cursor_visible(false), - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq)] -enum ActiveHiDpiMode { - Default, - Rounded, - Locked, -} - -/// DPI factor handling mode. -/// -/// Applications that use imgui-rs might want to customize the used DPI factor and not use -/// directly the value coming from winit. -/// -/// **Note: if you use a mode other than default and the DPI factor is adjusted, winit and imgui-rs -/// will use different logical coordinates, so be careful if you pass around logical size or -/// position values.** -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum HiDpiMode { - /// The DPI factor from winit is used directly without adjustment - Default, - /// The DPI factor from winit is rounded to an integer value. - /// - /// This prevents the user interface from becoming blurry with non-integer scaling. - Rounded, - /// The DPI factor from winit is ignored, and the included value is used instead. - /// - /// This is useful if you want to force some DPI factor (e.g. 1.0) and not care about the value - /// coming from winit. - Locked(f64), -} - -impl HiDpiMode { - fn apply(&self, hidpi_factor: f64) -> (ActiveHiDpiMode, f64) { - match *self { - HiDpiMode::Default => (ActiveHiDpiMode::Default, hidpi_factor), - HiDpiMode::Rounded => (ActiveHiDpiMode::Rounded, hidpi_factor.round()), - HiDpiMode::Locked(value) => (ActiveHiDpiMode::Locked, value), - } - } -} - -fn to_imgui_mouse_button(button: MouseButton) -> Option { - match button { - MouseButton::Left | MouseButton::Other(0) => Some(imgui::MouseButton::Left), - MouseButton::Right | MouseButton::Other(1) => Some(imgui::MouseButton::Right), - MouseButton::Middle | MouseButton::Other(2) => Some(imgui::MouseButton::Middle), - MouseButton::Other(3) => Some(imgui::MouseButton::Extra1), - MouseButton::Other(4) => Some(imgui::MouseButton::Extra2), - _ => None, - } -} - -fn to_imgui_key(key: winit::keyboard::Key, location: KeyLocation) -> Option { - match (key.as_ref(), location) { - (WinitKey::Named(NamedKey::Tab), _) => Some(Key::Tab), - (WinitKey::Named(NamedKey::ArrowLeft), _) => Some(Key::LeftArrow), - (WinitKey::Named(NamedKey::ArrowRight), _) => Some(Key::RightArrow), - (WinitKey::Named(NamedKey::ArrowUp), _) => Some(Key::UpArrow), - (WinitKey::Named(NamedKey::ArrowDown), _) => Some(Key::DownArrow), - (WinitKey::Named(NamedKey::PageUp), _) => Some(Key::PageUp), - (WinitKey::Named(NamedKey::PageDown), _) => Some(Key::PageDown), - (WinitKey::Named(NamedKey::Home), _) => Some(Key::Home), - (WinitKey::Named(NamedKey::End), _) => Some(Key::End), - (WinitKey::Named(NamedKey::Insert), _) => Some(Key::Insert), - (WinitKey::Named(NamedKey::Delete), _) => Some(Key::Delete), - (WinitKey::Named(NamedKey::Backspace), _) => Some(Key::Backspace), - (WinitKey::Named(NamedKey::Space), _) => Some(Key::Space), - (WinitKey::Named(NamedKey::Enter), KeyLocation::Standard) => Some(Key::Enter), - (WinitKey::Named(NamedKey::Enter), KeyLocation::Numpad) => Some(Key::KeypadEnter), - (WinitKey::Named(NamedKey::Escape), _) => Some(Key::Escape), - (WinitKey::Named(NamedKey::Control), KeyLocation::Left) => Some(Key::LeftCtrl), - (WinitKey::Named(NamedKey::Control), KeyLocation::Right) => Some(Key::RightCtrl), - (WinitKey::Named(NamedKey::Shift), KeyLocation::Left) => Some(Key::LeftShift), - (WinitKey::Named(NamedKey::Shift), KeyLocation::Right) => Some(Key::RightShift), - (WinitKey::Named(NamedKey::Alt), KeyLocation::Left) => Some(Key::LeftAlt), - (WinitKey::Named(NamedKey::Alt), KeyLocation::Right) => Some(Key::RightAlt), - (WinitKey::Named(NamedKey::Super), KeyLocation::Left) => Some(Key::LeftSuper), - (WinitKey::Named(NamedKey::Super), KeyLocation::Right) => Some(Key::RightSuper), - (WinitKey::Named(NamedKey::ContextMenu), _) => Some(Key::Menu), - (WinitKey::Named(NamedKey::F1), _) => Some(Key::F1), - (WinitKey::Named(NamedKey::F2), _) => Some(Key::F2), - (WinitKey::Named(NamedKey::F3), _) => Some(Key::F3), - (WinitKey::Named(NamedKey::F4), _) => Some(Key::F4), - (WinitKey::Named(NamedKey::F5), _) => Some(Key::F5), - (WinitKey::Named(NamedKey::F6), _) => Some(Key::F6), - (WinitKey::Named(NamedKey::F7), _) => Some(Key::F7), - (WinitKey::Named(NamedKey::F8), _) => Some(Key::F8), - (WinitKey::Named(NamedKey::F9), _) => Some(Key::F9), - (WinitKey::Named(NamedKey::F10), _) => Some(Key::F10), - (WinitKey::Named(NamedKey::F11), _) => Some(Key::F11), - (WinitKey::Named(NamedKey::F12), _) => Some(Key::F12), - (WinitKey::Named(NamedKey::CapsLock), _) => Some(Key::CapsLock), - (WinitKey::Named(NamedKey::ScrollLock), _) => Some(Key::ScrollLock), - (WinitKey::Named(NamedKey::NumLock), _) => Some(Key::NumLock), - (WinitKey::Named(NamedKey::PrintScreen), _) => Some(Key::PrintScreen), - (WinitKey::Named(NamedKey::Pause), _) => Some(Key::Pause), - (WinitKey::Character("0"), KeyLocation::Standard) => Some(Key::Alpha0), - (WinitKey::Character("1"), KeyLocation::Standard) => Some(Key::Alpha1), - (WinitKey::Character("2"), KeyLocation::Standard) => Some(Key::Alpha2), - (WinitKey::Character("3"), KeyLocation::Standard) => Some(Key::Alpha3), - (WinitKey::Character("4"), KeyLocation::Standard) => Some(Key::Alpha4), - (WinitKey::Character("5"), KeyLocation::Standard) => Some(Key::Alpha5), - (WinitKey::Character("6"), KeyLocation::Standard) => Some(Key::Alpha6), - (WinitKey::Character("7"), KeyLocation::Standard) => Some(Key::Alpha7), - (WinitKey::Character("8"), KeyLocation::Standard) => Some(Key::Alpha8), - (WinitKey::Character("9"), KeyLocation::Standard) => Some(Key::Alpha9), - (WinitKey::Character("0"), KeyLocation::Numpad) => Some(Key::Keypad0), - (WinitKey::Character("1"), KeyLocation::Numpad) => Some(Key::Keypad1), - (WinitKey::Character("2"), KeyLocation::Numpad) => Some(Key::Keypad2), - (WinitKey::Character("3"), KeyLocation::Numpad) => Some(Key::Keypad3), - (WinitKey::Character("4"), KeyLocation::Numpad) => Some(Key::Keypad4), - (WinitKey::Character("5"), KeyLocation::Numpad) => Some(Key::Keypad5), - (WinitKey::Character("6"), KeyLocation::Numpad) => Some(Key::Keypad6), - (WinitKey::Character("7"), KeyLocation::Numpad) => Some(Key::Keypad7), - (WinitKey::Character("8"), KeyLocation::Numpad) => Some(Key::Keypad8), - (WinitKey::Character("9"), KeyLocation::Numpad) => Some(Key::Keypad9), - (WinitKey::Character("a"), _) => Some(Key::A), - (WinitKey::Character("b"), _) => Some(Key::B), - (WinitKey::Character("c"), _) => Some(Key::C), - (WinitKey::Character("d"), _) => Some(Key::D), - (WinitKey::Character("e"), _) => Some(Key::E), - (WinitKey::Character("f"), _) => Some(Key::F), - (WinitKey::Character("g"), _) => Some(Key::G), - (WinitKey::Character("h"), _) => Some(Key::H), - (WinitKey::Character("i"), _) => Some(Key::I), - (WinitKey::Character("j"), _) => Some(Key::J), - (WinitKey::Character("k"), _) => Some(Key::K), - (WinitKey::Character("l"), _) => Some(Key::L), - (WinitKey::Character("m"), _) => Some(Key::M), - (WinitKey::Character("n"), _) => Some(Key::N), - (WinitKey::Character("o"), _) => Some(Key::O), - (WinitKey::Character("p"), _) => Some(Key::P), - (WinitKey::Character("q"), _) => Some(Key::Q), - (WinitKey::Character("r"), _) => Some(Key::R), - (WinitKey::Character("s"), _) => Some(Key::S), - (WinitKey::Character("t"), _) => Some(Key::T), - (WinitKey::Character("u"), _) => Some(Key::U), - (WinitKey::Character("v"), _) => Some(Key::V), - (WinitKey::Character("w"), _) => Some(Key::W), - (WinitKey::Character("x"), _) => Some(Key::X), - (WinitKey::Character("y"), _) => Some(Key::Y), - (WinitKey::Character("z"), _) => Some(Key::Z), - (WinitKey::Character("'"), _) => Some(Key::Apostrophe), - (WinitKey::Character(","), KeyLocation::Standard) => Some(Key::Comma), - (WinitKey::Character("-"), KeyLocation::Standard) => Some(Key::Minus), - (WinitKey::Character("-"), KeyLocation::Numpad) => Some(Key::KeypadSubtract), - (WinitKey::Character("."), KeyLocation::Standard) => Some(Key::Period), - (WinitKey::Character("."), KeyLocation::Numpad) => Some(Key::KeypadDecimal), - (WinitKey::Character("/"), KeyLocation::Standard) => Some(Key::Slash), - (WinitKey::Character("/"), KeyLocation::Numpad) => Some(Key::KeypadDivide), - (WinitKey::Character(";"), _) => Some(Key::Semicolon), - (WinitKey::Character("="), KeyLocation::Standard) => Some(Key::Equal), - (WinitKey::Character("="), KeyLocation::Numpad) => Some(Key::KeypadEqual), - (WinitKey::Character("["), _) => Some(Key::LeftBracket), - (WinitKey::Character("\\"), _) => Some(Key::Backslash), - (WinitKey::Character("]"), _) => Some(Key::RightBracket), - (WinitKey::Character("`"), _) => Some(Key::GraveAccent), - (WinitKey::Character("*"), KeyLocation::Numpad) => Some(Key::KeypadMultiply), - (WinitKey::Character("+"), KeyLocation::Numpad) => Some(Key::KeypadAdd), - _ => None, - } -} - -fn handle_key_modifier(io: &mut Io, key: &WinitKey, down: bool) { - match key { - WinitKey::Named(NamedKey::Shift) => io.add_key_event(imgui::Key::ModShift, down), - WinitKey::Named(NamedKey::Control) => io.add_key_event(imgui::Key::ModCtrl, down), - WinitKey::Named(NamedKey::Alt) => io.add_key_event(imgui::Key::ModAlt, down), - WinitKey::Named(NamedKey::Super) => io.add_key_event(imgui::Key::ModSuper, down), - _ => {} - } -} - -impl WinitPlatform { - /// Initializes a winit platform instance and configures imgui. - /// - /// This function configures imgui-rs in the following ways: - /// - /// * backend flags are updated - /// * keys are configured - /// * platform name is set - pub fn init(imgui: &mut Context) -> WinitPlatform { - let io = imgui.io_mut(); - io.backend_flags.insert(BackendFlags::HAS_MOUSE_CURSORS); - io.backend_flags.insert(BackendFlags::HAS_SET_MOUSE_POS); - imgui.set_platform_name(Some(format!( - "imgui-winit-support {}", - env!("CARGO_PKG_VERSION") - ))); - WinitPlatform { - hidpi_mode: ActiveHiDpiMode::Default, - hidpi_factor: 1.0, - cursor_cache: None, - } - } - /// Attaches the platform instance to a winit window. - /// - /// This function configures imgui-rs in the following ways: - /// - /// * framebuffer scale (= DPI factor) is set - /// * display size is set - pub fn attach_window(&mut self, io: &mut Io, window: &Window, hidpi_mode: HiDpiMode) { - let (hidpi_mode, hidpi_factor) = hidpi_mode.apply(window.scale_factor()); - self.hidpi_mode = hidpi_mode; - self.hidpi_factor = hidpi_factor; - io.display_framebuffer_scale = [hidpi_factor as f32, hidpi_factor as f32]; - let logical_size = window.inner_size().to_logical(hidpi_factor); - let logical_size = self.scale_size_from_winit(window, logical_size); - io.display_size = [logical_size.width as f32, logical_size.height as f32]; - } - /// Returns the current DPI factor. - /// - /// The value might not be the same as the winit DPI factor (depends on the used DPI mode) - pub fn hidpi_factor(&self) -> f64 { - self.hidpi_factor - } - /// Scales a logical size coming from winit using the current DPI mode. - /// - /// This utility function is useful if you are using a DPI mode other than default, and want - /// your application to use the same logical coordinates as imgui-rs. - pub fn scale_size_from_winit( - &self, - window: &Window, - logical_size: LogicalSize, - ) -> LogicalSize { - match self.hidpi_mode { - ActiveHiDpiMode::Default => logical_size, - _ => logical_size - .to_physical::(window.scale_factor()) - .to_logical(self.hidpi_factor), - } - } - /// Scales a logical position coming from winit using the current DPI mode. - /// - /// This utility function is useful if you are using a DPI mode other than default, and want - /// your application to use the same logical coordinates as imgui-rs. - pub fn scale_pos_from_winit( - &self, - window: &Window, - logical_pos: LogicalPosition, - ) -> LogicalPosition { - match self.hidpi_mode { - ActiveHiDpiMode::Default => logical_pos, - _ => logical_pos - .to_physical::(window.scale_factor()) - .to_logical(self.hidpi_factor), - } - } - /// Scales a logical position for winit using the current DPI mode. - /// - /// This utility function is useful if you are using a DPI mode other than default, and want - /// your application to use the same logical coordinates as imgui-rs. - pub fn scale_pos_for_winit( - &self, - window: &Window, - logical_pos: LogicalPosition, - ) -> LogicalPosition { - match self.hidpi_mode { - ActiveHiDpiMode::Default => logical_pos, - _ => logical_pos - .to_physical::(self.hidpi_factor) - .to_logical(window.scale_factor()), - } - } - /// Handles a winit event. - /// - /// This function performs the following actions (depends on the event): - /// - /// * window size / dpi factor changes are applied - /// * keyboard state is updated - /// * mouse state is updated - pub fn handle_event(&mut self, io: &mut Io, window: &Window, event: &Event) { - match *event { - Event::WindowEvent { - window_id, - ref event, - } if window_id == window.id() => { - self.handle_window_event(io, window, event); - } - // Track key release events outside our window. If we don't do this, - // we might never see the release event if some other window gets focus. - // Event::DeviceEvent { - // event: - // DeviceEvent::Key(RawKeyEvent { - // physical_key, - // state: ElementState::Released, - // }), - // .. - // } => { - // if let Some(key) = to_imgui_key(key) { - // io.add_key_event(key, false); - // } - // } - _ => (), - } - } - fn handle_window_event(&mut self, io: &mut Io, window: &Window, event: &WindowEvent) { - match *event { - WindowEvent::Resized(physical_size) => { - let logical_size = physical_size.to_logical(window.scale_factor()); - let logical_size = self.scale_size_from_winit(window, logical_size); - io.display_size = [logical_size.width as f32, logical_size.height as f32]; - } - WindowEvent::ScaleFactorChanged { scale_factor, .. } => { - let hidpi_factor = match self.hidpi_mode { - ActiveHiDpiMode::Default => scale_factor, - ActiveHiDpiMode::Rounded => scale_factor.round(), - _ => return, - }; - // Mouse position needs to be changed while we still have both the old and the new - // values - if io.mouse_pos[0].is_finite() && io.mouse_pos[1].is_finite() { - io.mouse_pos = [ - io.mouse_pos[0] * (hidpi_factor / self.hidpi_factor) as f32, - io.mouse_pos[1] * (hidpi_factor / self.hidpi_factor) as f32, - ]; - } - self.hidpi_factor = hidpi_factor; - io.display_framebuffer_scale = [hidpi_factor as f32, hidpi_factor as f32]; - // Window size might change too if we are using DPI rounding - let logical_size = window.inner_size().to_logical(scale_factor); - let logical_size = self.scale_size_from_winit(window, logical_size); - io.display_size = [logical_size.width as f32, logical_size.height as f32]; - } - WindowEvent::ModifiersChanged(modifiers) => { - let state = modifiers.state(); - // We need to track modifiers separately because some system like macOS, will - // not reliably send modifier states during certain events like ScreenCapture. - // Gotta let the people show off their pretty imgui widgets! - io.add_key_event(Key::ModShift, state.shift_key()); - io.add_key_event(Key::ModCtrl, state.control_key()); - io.add_key_event(Key::ModAlt, state.alt_key()); - io.add_key_event(Key::ModSuper, state.super_key()); - } - WindowEvent::KeyboardInput { ref event, .. } => { - if let Some(txt) = &event.text { - for ch in txt.chars() { - if ch != '\u{7f}' { - io.add_input_character(ch) - } - } - } - - let key = event.key_without_modifiers(); - let pressed = event.state == ElementState::Pressed; - - // We map both left and right ctrl to `ModCtrl`, etc. - // imgui is told both "left control is pressed" and - // "consider the control key is pressed". Allows - // applications to use either general "ctrl" or a - // specific key. Same applies to other modifiers. - // https://github.com/ocornut/imgui/issues/5047 - handle_key_modifier(io, &key, pressed); - - // Add main key event - if let Some(key) = to_imgui_key(key, event.location) { - io.add_key_event(key, pressed); - } - } - WindowEvent::CursorMoved { position, .. } => { - let position = position.to_logical(window.scale_factor()); - let position = self.scale_pos_from_winit(window, position); - io.add_mouse_pos_event([position.x as f32, position.y as f32]); - } - WindowEvent::MouseWheel { - delta, - phase: TouchPhase::Moved, - .. - } => { - let (h, v) = match delta { - MouseScrollDelta::LineDelta(h, v) => (h, v), - MouseScrollDelta::PixelDelta(pos) => { - let pos = pos.to_logical::(self.hidpi_factor); - let h = match pos.x.partial_cmp(&0.0) { - Some(Ordering::Greater) => 1.0, - Some(Ordering::Less) => -1.0, - _ => 0.0, - }; - let v = match pos.y.partial_cmp(&0.0) { - Some(Ordering::Greater) => 1.0, - Some(Ordering::Less) => -1.0, - _ => 0.0, - }; - (h, v) - } - }; - io.add_mouse_wheel_event([h, v]); - } - WindowEvent::MouseInput { state, button, .. } => { - if let Some(mb) = to_imgui_mouse_button(button) { - let pressed = state == ElementState::Pressed; - io.add_mouse_button_event(mb, pressed); - } - } - WindowEvent::Focused(newly_focused) => { - if !newly_focused { - // Set focus-lost to avoid stuck keys (like 'alt' - // when alt-tabbing) - io.app_focus_lost = true; - } - } - _ => (), - } - } - /// Frame preparation callback. - /// - /// Call this before calling the imgui-rs context `frame` function. - /// This function performs the following actions: - /// - /// * mouse cursor is repositioned (if requested by imgui-rs) - pub fn prepare_frame(&self, io: &mut Io, window: &Window) -> Result<(), ExternalError> { - if io.want_set_mouse_pos { - let logical_pos = self.scale_pos_for_winit( - window, - LogicalPosition::new(f64::from(io.mouse_pos[0]), f64::from(io.mouse_pos[1])), - ); - window.set_cursor_position(logical_pos) - } else { - Ok(()) - } - } - - /// Render preparation callback. - /// - /// Call this before calling the imgui-rs UI `render_with`/`render` function. - /// This function performs the following actions: - /// - /// * mouse cursor is changed and/or hidden (if requested by imgui-rs) - pub fn prepare_render(&mut self, ui: &Ui, window: &Window) { - let io = ui.io(); - if !io - .config_flags - .contains(ConfigFlags::NO_MOUSE_CURSOR_CHANGE) - { - let cursor = CursorSettings { - cursor: ui.mouse_cursor(), - draw_cursor: io.mouse_draw_cursor, - }; - if self.cursor_cache != Some(cursor) { - cursor.apply(window); - self.cursor_cache = Some(cursor); - } - } - } -}