mirror of
https://github.com/eliasstepanik/imgui-rs.git
synced 2026-01-10 21:18:36 +00:00
it's going, but it doesn't actually work
This commit is contained in:
parent
8e3da3ba15
commit
4a8bf5cd9b
@ -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",
|
||||
]
|
||||
|
||||
@ -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" }
|
||||
|
||||
@ -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"
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
@ -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<WindowSurface>) {
|
||||
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::<WindowSurface>::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)
|
||||
}
|
||||
@ -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<vertex::BufferCreationError> for RendererError {
|
||||
fn from(e: vertex::BufferCreationError) -> RendererError {
|
||||
RendererError::Vertex(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<index::BufferCreationError> for RendererError {
|
||||
fn from(e: index::BufferCreationError) -> RendererError {
|
||||
RendererError::Index(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ProgramChooserCreationError> for RendererError {
|
||||
fn from(e: ProgramChooserCreationError) -> RendererError {
|
||||
RendererError::Program(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TextureCreationError> for RendererError {
|
||||
fn from(e: TextureCreationError) -> RendererError {
|
||||
RendererError::Texture(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DrawError> for RendererError {
|
||||
fn from(e: DrawError) -> RendererError {
|
||||
RendererError::Draw(e)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Texture {
|
||||
pub texture: Rc<Texture2d>,
|
||||
pub sampler: SamplerBehavior,
|
||||
}
|
||||
|
||||
pub struct Renderer {
|
||||
ctx: Rc<Context>,
|
||||
program: Program,
|
||||
font_texture: Texture,
|
||||
textures: Textures<Texture>,
|
||||
}
|
||||
|
||||
#[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<F: Facade>(
|
||||
ctx: &mut imgui::Context,
|
||||
facade: &F,
|
||||
) -> Result<Renderer, RendererError> {
|
||||
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<Texture> {
|
||||
&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<T: Surface>(
|
||||
&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::<GliumDrawVert>()
|
||||
})?;
|
||||
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<Context>,
|
||||
) -> Result<Texture, RendererError> {
|
||||
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<F: Facade>(facade: &F) -> Result<Program, ProgramChooserCreationError> {
|
||||
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,
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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 = []
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
@ -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<WindowSurface>,
|
||||
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::<WindowSurface>::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)
|
||||
}
|
||||
@ -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");
|
||||
}
|
||||
@ -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");
|
||||
}
|
||||
@ -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::<glow::Texture>::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<glow::Texture>) -> 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<glow::Texture>,
|
||||
) -> 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<glow::Texture>) -> 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);
|
||||
}
|
||||
}
|
||||
@ -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<glow::Context>,
|
||||
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");
|
||||
}
|
||||
@ -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<ContextApi>,
|
||||
) -> (
|
||||
EventLoop<()>,
|
||||
Window,
|
||||
Surface<WindowSurface>,
|
||||
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::<WindowSurface>::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: <glow::Context as HasContext>::Program,
|
||||
pub vertex_array: <glow::Context as HasContext>::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -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<G: glow::HasContext>(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
|
||||
/// `<major>.<minor>[.<release>][ <vendor specific information>]`
|
||||
/// for full-fat OpenGL, and
|
||||
/// `OpenGL ES <major>.<minor>[.<release>][ <vendor specific information>]`
|
||||
/// 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<std::cmp::Ordering> {
|
||||
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<G: glow::HasContext>(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
|
||||
/// `<major>.<minor>[.<release>][ <vendor specific information>]`
|
||||
/// for full-fat OpenGL, and
|
||||
/// `OpenGL ES GLSL ES <major>.<minor>[.<release>][ <vendor specific information>]`
|
||||
/// 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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"] }
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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<Cursor>, /* 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)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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"
|
||||
@ -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::<WindowSurface>::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");
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
}
|
||||
@ -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 }
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
@ -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
|
||||
@ -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<CursorSettings>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
struct CursorSettings {
|
||||
cursor: Option<imgui::MouseCursor>,
|
||||
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<imgui::MouseButton> {
|
||||
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<Key> {
|
||||
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<f64>,
|
||||
) -> LogicalSize<f64> {
|
||||
match self.hidpi_mode {
|
||||
ActiveHiDpiMode::Default => logical_size,
|
||||
_ => logical_size
|
||||
.to_physical::<f64>(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<f64>,
|
||||
) -> LogicalPosition<f64> {
|
||||
match self.hidpi_mode {
|
||||
ActiveHiDpiMode::Default => logical_pos,
|
||||
_ => logical_pos
|
||||
.to_physical::<f64>(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<f64>,
|
||||
) -> LogicalPosition<f64> {
|
||||
match self.hidpi_mode {
|
||||
ActiveHiDpiMode::Default => logical_pos,
|
||||
_ => logical_pos
|
||||
.to_physical::<f64>(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<T>(&mut self, io: &mut Io, window: &Window, event: &Event<T>) {
|
||||
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::<f64>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user