mirror of
https://github.com/eliasstepanik/imgui-rs.git
synced 2026-01-10 21:18:36 +00:00
Added basic combined renderer
This commit is contained in:
parent
14531a074c
commit
6bb28843b2
@ -6,6 +6,7 @@ members = [
|
||||
"imgui-glow-renderer",
|
||||
"imgui-sdl2-support",
|
||||
"imgui-winit-support",
|
||||
"imgui-winit-glow-renderer-viewports",
|
||||
"imgui-examples",
|
||||
"xtask",
|
||||
]
|
||||
|
||||
16
imgui-winit-glow-renderer-viewports/Cargo.toml
Normal file
16
imgui-winit-glow-renderer-viewports/Cargo.toml
Normal file
@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "imgui-winit-glow-renderer-viewports"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
imgui = { version="0.9.0", path="../imgui", features=["docking"] }
|
||||
|
||||
glow = "0.11.2"
|
||||
glutin = "0.30.3"
|
||||
raw-window-handle = "0.5.0"
|
||||
winit = "0.27.5"
|
||||
thiserror = "1.0.38"
|
||||
glutin-winit = "0.2.1"
|
||||
116
imgui-winit-glow-renderer-viewports/examples/basic.rs
Normal file
116
imgui-winit-glow-renderer-viewports/examples/basic.rs
Normal file
@ -0,0 +1,116 @@
|
||||
use std::{ffi::CString, num::NonZeroU32};
|
||||
|
||||
use glow::{Context, HasContext};
|
||||
use glutin::{
|
||||
config::ConfigTemplateBuilder,
|
||||
context::ContextAttributesBuilder,
|
||||
display::GetGlDisplay,
|
||||
prelude::{GlDisplay, NotCurrentGlContextSurfaceAccessor, PossiblyCurrentContextGlSurfaceAccessor},
|
||||
surface::{SurfaceAttributesBuilder, WindowSurface, GlSurface},
|
||||
};
|
||||
use glutin_winit::DisplayBuilder;
|
||||
use imgui::ConfigFlags;
|
||||
use imgui_winit_glow_renderer_viewports::Renderer;
|
||||
use raw_window_handle::HasRawWindowHandle;
|
||||
use winit::{dpi::LogicalSize, event_loop::EventLoop, window::WindowBuilder};
|
||||
|
||||
fn main() {
|
||||
let event_loop = EventLoop::new();
|
||||
|
||||
let window_builder = WindowBuilder::new()
|
||||
.with_inner_size(LogicalSize::new(800.0, 600.0))
|
||||
.with_visible(true)
|
||||
.with_resizable(true)
|
||||
.with_title("Viewports example");
|
||||
|
||||
let template_builder = ConfigTemplateBuilder::new();
|
||||
let (window, gl_config) = DisplayBuilder::new()
|
||||
.with_window_builder(Some(window_builder))
|
||||
.build(&event_loop, template_builder, |mut configs| {
|
||||
configs.next().unwrap()
|
||||
})
|
||||
.expect("Failed to create main window");
|
||||
|
||||
let window = window.unwrap();
|
||||
|
||||
let context_attribs = ContextAttributesBuilder::new().build(Some(window.raw_window_handle()));
|
||||
let context = unsafe {
|
||||
gl_config
|
||||
.display()
|
||||
.create_context(&gl_config, &context_attribs)
|
||||
.expect("Failed to create main context")
|
||||
};
|
||||
|
||||
let size = window.inner_size();
|
||||
let surface_attribs = SurfaceAttributesBuilder::<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);
|
||||
|
||||
let mut renderer = Renderer::new(&mut imgui, &window, &glow).expect("Failed to init Renderer");
|
||||
|
||||
event_loop.run(move |event, window_target, control_flow| {
|
||||
control_flow.set_poll();
|
||||
|
||||
renderer.handle_event(&mut imgui, &window, &event);
|
||||
|
||||
match event {
|
||||
winit::event::Event::MainEventsCleared => {
|
||||
window.request_redraw();
|
||||
},
|
||||
winit::event::Event::RedrawRequested(_) => {
|
||||
let ui = imgui.frame();
|
||||
|
||||
ui.show_demo_window(&mut true);
|
||||
|
||||
ui.end_frame_early();
|
||||
|
||||
imgui.update_platform_windows();
|
||||
renderer.update_viewports(&mut imgui, window_target, &glow).expect("Failed to update viewports");
|
||||
|
||||
let draw_data = imgui.render();
|
||||
|
||||
context.make_current(&surface).expect("Failed to make current");
|
||||
|
||||
unsafe {
|
||||
glow.clear(glow::COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
renderer.render(&window, &glow, draw_data).expect("Failed to render main viewport");
|
||||
|
||||
surface.swap_buffers(&context).expect("Failed to swap buffers");
|
||||
|
||||
renderer.render_viewports(&glow, &mut imgui).expect("Failed to render viewports");
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
});
|
||||
}
|
||||
13
imgui-winit-glow-renderer-viewports/src/fragment_shader.glsl
Normal file
13
imgui-winit-glow-renderer-viewports/src/fragment_shader.glsl
Normal file
@ -0,0 +1,13 @@
|
||||
#version 450 core
|
||||
|
||||
in vec2 v2f_UV;
|
||||
in vec4 v2f_Color;
|
||||
|
||||
layout(location = 0) uniform sampler2D u_FontTexture;
|
||||
|
||||
layout(location = 0) out vec4 out_Color;
|
||||
|
||||
void main() {
|
||||
vec4 tex = texture(u_FontTexture, v2f_UV);
|
||||
out_Color = v2f_Color * tex;
|
||||
}
|
||||
767
imgui-winit-glow-renderer-viewports/src/lib.rs
Normal file
767
imgui-winit-glow-renderer-viewports/src/lib.rs
Normal file
@ -0,0 +1,767 @@
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
collections::{HashMap, VecDeque},
|
||||
num::NonZeroU32,
|
||||
ptr::null_mut,
|
||||
rc::Rc, slice,
|
||||
};
|
||||
|
||||
use glow::HasContext;
|
||||
use glutin::{
|
||||
config::ConfigTemplateBuilder,
|
||||
context::{ContextAttributesBuilder, NotCurrentContext},
|
||||
display::GetGlDisplay,
|
||||
prelude::{GlDisplay, NotCurrentGlContextSurfaceAccessor, PossiblyCurrentGlContext},
|
||||
surface::{Surface, SurfaceAttributesBuilder, WindowSurface, GlSurface},
|
||||
};
|
||||
use glutin_winit::DisplayBuilder;
|
||||
use imgui::{BackendFlags, Id, Key, ViewportFlags};
|
||||
use raw_window_handle::HasRawWindowHandle;
|
||||
use thiserror::Error;
|
||||
use winit::{
|
||||
dpi::{PhysicalPosition, PhysicalSize},
|
||||
event::{DeviceEvent, ElementState, KeyboardInput, TouchPhase, VirtualKeyCode},
|
||||
event_loop::EventLoopWindowTarget,
|
||||
window::{Window, WindowBuilder},
|
||||
};
|
||||
|
||||
const VERTEX_SHADER: &str = include_str!("vertex_shader.glsl");
|
||||
const FRAGMENT_SHADER: &str = include_str!("fragment_shader.glsl");
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum RendererError {
|
||||
#[error("OpenGL object creation failed: {0}")]
|
||||
GlObjectCreationError(String),
|
||||
#[error("Failed to create glutin Display")]
|
||||
GlutinDisplay,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ViewportEvent {
|
||||
Create(Id),
|
||||
Destroy(Id),
|
||||
SetPos(Id, [f32; 2]),
|
||||
SetSize(Id, [f32; 2]),
|
||||
SetVisible(Id),
|
||||
SetFocus(Id),
|
||||
SetTitle(Id, String),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Renderer {
|
||||
gl_objects: GlObjects,
|
||||
glutin_config: Option<glutin::config::Config>,
|
||||
extra_windows: HashMap<
|
||||
Id,
|
||||
(
|
||||
Window,
|
||||
Option<NotCurrentContext>,
|
||||
Surface<WindowSurface>,
|
||||
GlObjects,
|
||||
),
|
||||
>,
|
||||
event_queue: Rc<RefCell<VecDeque<ViewportEvent>>>,
|
||||
font_width: u32,
|
||||
font_height: u32,
|
||||
font_pixels: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct GlObjects {
|
||||
program: glow::Program,
|
||||
font_texture: glow::Texture,
|
||||
vao: glow::VertexArray,
|
||||
vbo: glow::Buffer,
|
||||
ibo: glow::Buffer,
|
||||
}
|
||||
|
||||
impl GlObjects {
|
||||
pub fn new(
|
||||
font_width: u32,
|
||||
font_height: u32,
|
||||
font_pixels: &[u8],
|
||||
glow: &glow::Context,
|
||||
) -> Result<Self, RendererError> {
|
||||
let program = unsafe {
|
||||
let vertex_shader = glow
|
||||
.create_shader(glow::VERTEX_SHADER)
|
||||
.map_err(|e| RendererError::GlObjectCreationError(e))?;
|
||||
glow.shader_source(vertex_shader, VERTEX_SHADER);
|
||||
glow.compile_shader(vertex_shader);
|
||||
assert!(
|
||||
glow.get_shader_compile_status(vertex_shader),
|
||||
"Vertex Shader contains error"
|
||||
);
|
||||
|
||||
let fragment_shader = glow
|
||||
.create_shader(glow::FRAGMENT_SHADER)
|
||||
.map_err(|e| RendererError::GlObjectCreationError(e))?;
|
||||
glow.shader_source(fragment_shader, FRAGMENT_SHADER);
|
||||
glow.compile_shader(fragment_shader);
|
||||
assert!(
|
||||
glow.get_shader_compile_status(fragment_shader),
|
||||
"Fragment Shader contains error"
|
||||
);
|
||||
|
||||
let program = glow
|
||||
.create_program()
|
||||
.map_err(|e| RendererError::GlObjectCreationError(e))?;
|
||||
glow.attach_shader(program, vertex_shader);
|
||||
glow.attach_shader(program, fragment_shader);
|
||||
glow.link_program(program);
|
||||
assert!(
|
||||
glow.get_program_link_status(program),
|
||||
"Program contains error"
|
||||
);
|
||||
|
||||
glow.delete_shader(vertex_shader);
|
||||
glow.delete_shader(fragment_shader);
|
||||
|
||||
program
|
||||
};
|
||||
|
||||
let font_texture = unsafe {
|
||||
let tex = glow
|
||||
.create_texture()
|
||||
.map_err(|e| RendererError::GlObjectCreationError(e))?;
|
||||
glow.bind_texture(glow::TEXTURE_2D, Some(tex));
|
||||
glow.tex_parameter_i32(
|
||||
glow::TEXTURE_2D,
|
||||
glow::TEXTURE_MAG_FILTER,
|
||||
glow::LINEAR as i32,
|
||||
);
|
||||
glow.tex_parameter_i32(
|
||||
glow::TEXTURE_2D,
|
||||
glow::TEXTURE_MIN_FILTER,
|
||||
glow::LINEAR as i32,
|
||||
);
|
||||
glow.tex_parameter_i32(
|
||||
glow::TEXTURE_2D,
|
||||
glow::TEXTURE_WRAP_S,
|
||||
glow::CLAMP_TO_EDGE as i32,
|
||||
);
|
||||
glow.tex_parameter_i32(
|
||||
glow::TEXTURE_2D,
|
||||
glow::TEXTURE_WRAP_T,
|
||||
glow::CLAMP_TO_EDGE as i32,
|
||||
);
|
||||
glow.tex_image_2d(
|
||||
glow::TEXTURE_2D,
|
||||
0,
|
||||
glow::RGBA as i32,
|
||||
font_width as i32,
|
||||
font_height as i32,
|
||||
0,
|
||||
glow::RGBA,
|
||||
glow::UNSIGNED_BYTE,
|
||||
Some(font_pixels),
|
||||
);
|
||||
|
||||
tex
|
||||
};
|
||||
|
||||
let vao = unsafe {
|
||||
let vao = glow
|
||||
.create_vertex_array()
|
||||
.map_err(|e| RendererError::GlObjectCreationError(e))?;
|
||||
|
||||
glow.bind_vertex_array(Some(vao));
|
||||
glow.enable_vertex_attrib_array(0);
|
||||
glow.enable_vertex_attrib_array(1);
|
||||
glow.enable_vertex_attrib_array(2);
|
||||
glow.vertex_attrib_pointer_f32(0, 2, glow::FLOAT, false, 20, 0);
|
||||
glow.vertex_attrib_pointer_f32(0, 2, glow::FLOAT, false, 20, 8);
|
||||
glow.vertex_attrib_pointer_f32(0, 4, glow::UNSIGNED_BYTE, true, 20, 16);
|
||||
|
||||
vao
|
||||
};
|
||||
|
||||
let vbo = unsafe {
|
||||
glow.create_buffer()
|
||||
.map_err(|e| RendererError::GlObjectCreationError(e))?
|
||||
};
|
||||
let ibo = unsafe {
|
||||
glow.create_buffer()
|
||||
.map_err(|e| RendererError::GlObjectCreationError(e))?
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
program,
|
||||
font_texture,
|
||||
vao,
|
||||
vbo,
|
||||
ibo,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Renderer {
|
||||
pub fn new(
|
||||
imgui: &mut imgui::Context,
|
||||
main_window: &Window,
|
||||
gl_context: &glow::Context,
|
||||
) -> Result<Self, RendererError> {
|
||||
let io = imgui.io_mut();
|
||||
|
||||
io.backend_flags.insert(BackendFlags::HAS_MOUSE_CURSORS);
|
||||
io.backend_flags.insert(BackendFlags::HAS_SET_MOUSE_POS);
|
||||
io.backend_flags
|
||||
.insert(BackendFlags::PLATFORM_HAS_VIEWPORTS);
|
||||
io.backend_flags
|
||||
.insert(BackendFlags::RENDERER_HAS_VIEWPORTS);
|
||||
io.backend_flags
|
||||
.insert(BackendFlags::RENDERER_HAS_VTX_OFFSET);
|
||||
|
||||
io[Key::Tab] = VirtualKeyCode::Tab as _;
|
||||
io[Key::LeftArrow] = VirtualKeyCode::Left as _;
|
||||
io[Key::RightArrow] = VirtualKeyCode::Right as _;
|
||||
io[Key::UpArrow] = VirtualKeyCode::Up as _;
|
||||
io[Key::DownArrow] = VirtualKeyCode::Down as _;
|
||||
io[Key::PageUp] = VirtualKeyCode::PageUp as _;
|
||||
io[Key::PageDown] = VirtualKeyCode::PageDown as _;
|
||||
io[Key::Home] = VirtualKeyCode::Home as _;
|
||||
io[Key::End] = VirtualKeyCode::End as _;
|
||||
io[Key::Insert] = VirtualKeyCode::Insert as _;
|
||||
io[Key::Delete] = VirtualKeyCode::Delete as _;
|
||||
io[Key::Backspace] = VirtualKeyCode::Back as _;
|
||||
io[Key::Space] = VirtualKeyCode::Space as _;
|
||||
io[Key::Enter] = VirtualKeyCode::Return as _;
|
||||
io[Key::Escape] = VirtualKeyCode::Escape as _;
|
||||
io[Key::KeyPadEnter] = VirtualKeyCode::NumpadEnter as _;
|
||||
io[Key::A] = VirtualKeyCode::A as _;
|
||||
io[Key::C] = VirtualKeyCode::C as _;
|
||||
io[Key::V] = VirtualKeyCode::V as _;
|
||||
io[Key::X] = VirtualKeyCode::X as _;
|
||||
io[Key::Y] = VirtualKeyCode::Y as _;
|
||||
io[Key::Z] = VirtualKeyCode::Z as _;
|
||||
|
||||
let window_size = main_window.inner_size().cast::<f32>();
|
||||
io.display_size = [window_size.width, window_size.height];
|
||||
io.display_framebuffer_scale = [1.0, 1.0];
|
||||
|
||||
let viewport = imgui.main_viewport_mut();
|
||||
|
||||
let main_pos = main_window.inner_position().unwrap().cast::<f32>();
|
||||
|
||||
viewport.pos = [main_pos.x, main_pos.y];
|
||||
viewport.work_pos = viewport.pos;
|
||||
viewport.size = [window_size.width, window_size.height];
|
||||
viewport.work_size = viewport.size;
|
||||
viewport.dpi_scale = 1.0;
|
||||
viewport.platform_user_data = Box::into_raw(Box::new(ViewportData {
|
||||
pos: [main_pos.x, main_pos.y],
|
||||
size: [window_size.width, window_size.height],
|
||||
focus: true,
|
||||
minimized: false,
|
||||
}))
|
||||
.cast();
|
||||
|
||||
let mut monitors = Vec::new();
|
||||
for monitor in main_window.available_monitors() {
|
||||
monitors.push(imgui::PlatformMonitor {
|
||||
main_pos: [monitor.position().x as f32, monitor.position().y as f32],
|
||||
main_size: [monitor.size().width as f32, monitor.size().height as f32],
|
||||
work_pos: [monitor.position().x as f32, monitor.position().y as f32],
|
||||
work_size: [monitor.size().width as f32, monitor.size().height as f32],
|
||||
dpi_scale: 1.0,
|
||||
});
|
||||
}
|
||||
imgui
|
||||
.platform_io_mut()
|
||||
.monitors
|
||||
.replace_from_slice(&monitors);
|
||||
|
||||
imgui.set_platform_name(Some(format!(
|
||||
"imgui-winit-glow-renderer-viewports {}",
|
||||
env!("CARGO_PKG_VERSION")
|
||||
)));
|
||||
imgui.set_renderer_name(Some(format!(
|
||||
"imgui-winit-glow-renderer-viewports {}",
|
||||
env!("CARGO_PKG_VERSION")
|
||||
)));
|
||||
|
||||
let event_queue = Rc::new(RefCell::new(VecDeque::new()));
|
||||
|
||||
imgui.set_platform_backend(PlatformBackend {
|
||||
event_queue: event_queue.clone(),
|
||||
});
|
||||
imgui.set_renderer_backend(RendererBackend {});
|
||||
|
||||
let font_tex = imgui.fonts().build_rgba32_texture();
|
||||
let gl_objects =
|
||||
GlObjects::new(font_tex.width, font_tex.height, font_tex.data, gl_context)?;
|
||||
|
||||
Ok(Self {
|
||||
gl_objects,
|
||||
glutin_config: None,
|
||||
extra_windows: HashMap::new(),
|
||||
event_queue: Rc::new(RefCell::new(VecDeque::new())),
|
||||
font_width: font_tex.width,
|
||||
font_height: font_tex.height,
|
||||
font_pixels: font_tex.data.to_vec(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn handle_event<T>(
|
||||
&mut self,
|
||||
imgui: &mut imgui::Context,
|
||||
main_window: &Window,
|
||||
event: &winit::event::Event<T>,
|
||||
) {
|
||||
match *event {
|
||||
winit::event::Event::WindowEvent {
|
||||
window_id,
|
||||
ref event,
|
||||
} => {
|
||||
let viewport = if window_id == main_window.id() {
|
||||
imgui.main_viewport_mut()
|
||||
} else {
|
||||
if let Some(id) = self.extra_windows.iter().find_map(|(id, (wnd, _, _, _))| {
|
||||
if wnd.id() == window_id {
|
||||
Some(*id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) {
|
||||
if let Some(viewport) = imgui.viewport_by_id_mut(id) {
|
||||
viewport
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
match *event {
|
||||
winit::event::WindowEvent::Resized(new_size) => {
|
||||
viewport.size = [new_size.width as f32, new_size.height as f32];
|
||||
viewport.work_size = viewport.size;
|
||||
|
||||
if window_id == main_window.id() {
|
||||
imgui.io_mut().display_size =
|
||||
[new_size.width as f32, new_size.height as f32];
|
||||
}
|
||||
}
|
||||
winit::event::WindowEvent::Moved(new_pos) => {
|
||||
viewport.pos = [new_pos.x as f32, new_pos.y as f32];
|
||||
viewport.work_pos = viewport.pos;
|
||||
}
|
||||
winit::event::WindowEvent::CloseRequested if window_id != main_window.id() => {
|
||||
viewport.platform_request_close = true;
|
||||
}
|
||||
winit::event::WindowEvent::ReceivedCharacter(c) => {
|
||||
imgui.io_mut().add_input_character(c);
|
||||
}
|
||||
winit::event::WindowEvent::Focused(f) => unsafe {
|
||||
(*(viewport.platform_user_data.cast::<ViewportData>())).focus = f;
|
||||
},
|
||||
winit::event::WindowEvent::KeyboardInput {
|
||||
input:
|
||||
KeyboardInput {
|
||||
virtual_keycode: Some(key),
|
||||
state: ElementState::Pressed,
|
||||
..
|
||||
},
|
||||
..
|
||||
} => {
|
||||
imgui.io_mut().keys_down[key as usize] = true;
|
||||
}
|
||||
winit::event::WindowEvent::CursorMoved { position, .. } => {
|
||||
imgui.io_mut().mouse_pos = [position.x as f32, position.y as f32];
|
||||
}
|
||||
winit::event::WindowEvent::MouseWheel {
|
||||
delta,
|
||||
phase: TouchPhase::Moved,
|
||||
..
|
||||
} => match delta {
|
||||
winit::event::MouseScrollDelta::LineDelta(h, v) => {
|
||||
imgui.io_mut().mouse_wheel_h = h;
|
||||
imgui.io_mut().mouse_wheel = v;
|
||||
}
|
||||
winit::event::MouseScrollDelta::PixelDelta(pos) => {
|
||||
imgui.io_mut().mouse_wheel_h += if pos.x > 0.0 {
|
||||
1.0
|
||||
} else if pos.x < 0.0 {
|
||||
-1.0
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
imgui.io_mut().mouse_wheel += if pos.y > 0.0 {
|
||||
1.0
|
||||
} else if pos.y < 0.0 {
|
||||
-1.0
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
}
|
||||
},
|
||||
winit::event::WindowEvent::MouseInput { state, button, .. } => {
|
||||
let state = state == ElementState::Pressed;
|
||||
|
||||
match button {
|
||||
winit::event::MouseButton::Left => {
|
||||
imgui.io_mut().mouse_down[0] = state;
|
||||
}
|
||||
winit::event::MouseButton::Right => {
|
||||
imgui.io_mut().mouse_down[1] = state;
|
||||
}
|
||||
winit::event::MouseButton::Middle => {
|
||||
imgui.io_mut().mouse_down[2] = state;
|
||||
}
|
||||
winit::event::MouseButton::Other(index @ 0..=4) => {
|
||||
imgui.io_mut().mouse_down[index as usize] = state;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
winit::event::Event::DeviceEvent {
|
||||
event:
|
||||
DeviceEvent::Key(KeyboardInput {
|
||||
virtual_keycode: Some(key),
|
||||
state: ElementState::Released,
|
||||
..
|
||||
}),
|
||||
..
|
||||
} => {
|
||||
imgui.io_mut().keys_down[key as usize] = false;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_viewports<T>(
|
||||
&mut self,
|
||||
imgui: &mut imgui::Context,
|
||||
window_target: &EventLoopWindowTarget<T>,
|
||||
glow: &glow::Context,
|
||||
) -> Result<(), RendererError> {
|
||||
loop {
|
||||
let event = self.event_queue.borrow_mut().pop_front();
|
||||
let event = if let Some(event) = event {
|
||||
event
|
||||
} else {
|
||||
break;
|
||||
};
|
||||
|
||||
match event {
|
||||
ViewportEvent::Create(id) => {
|
||||
if let Some(viewport) = imgui.viewport_by_id_mut(id) {
|
||||
let extra_window =
|
||||
self.create_extra_window(viewport, window_target, glow)?;
|
||||
self.extra_windows.insert(id, extra_window);
|
||||
}
|
||||
}
|
||||
ViewportEvent::Destroy(id) => {
|
||||
self.extra_windows.remove(&id);
|
||||
}
|
||||
ViewportEvent::SetPos(id, pos) => {
|
||||
if let Some((wnd, _, _, _)) = self.extra_windows.get(&id) {
|
||||
wnd.set_outer_position(PhysicalPosition::new(pos[0], pos[1]));
|
||||
}
|
||||
}
|
||||
ViewportEvent::SetSize(id, size) => {
|
||||
if let Some((wnd, _, _, _)) = self.extra_windows.get(&id) {
|
||||
wnd.set_inner_size(PhysicalSize::new(size[0], size[1]));
|
||||
}
|
||||
}
|
||||
ViewportEvent::SetVisible(id) => {
|
||||
if let Some((wnd, _, _, _)) = self.extra_windows.get(&id) {
|
||||
wnd.set_visible(true);
|
||||
}
|
||||
}
|
||||
ViewportEvent::SetFocus(id) => {
|
||||
if let Some((wnd, _, _, _)) = self.extra_windows.get(&id) {
|
||||
wnd.focus_window();
|
||||
}
|
||||
}
|
||||
ViewportEvent::SetTitle(id, title) => {
|
||||
if let Some((wnd, _, _, _)) = self.extra_windows.get(&id) {
|
||||
wnd.set_title(&title);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_extra_window<T>(
|
||||
&mut self,
|
||||
viewport: &mut imgui::Viewport,
|
||||
window_target: &EventLoopWindowTarget<T>,
|
||||
glow: &glow::Context,
|
||||
) -> Result<
|
||||
(
|
||||
Window,
|
||||
Option<NotCurrentContext>,
|
||||
Surface<WindowSurface>,
|
||||
GlObjects,
|
||||
),
|
||||
RendererError,
|
||||
> {
|
||||
let window_builder = WindowBuilder::new()
|
||||
.with_position(PhysicalPosition::new(viewport.pos[0], viewport.pos[1]))
|
||||
.with_inner_size(PhysicalSize::new(viewport.size[0], viewport.size[1]))
|
||||
.with_visible(false)
|
||||
.with_resizable(true)
|
||||
.with_decorations(!viewport.flags.contains(ViewportFlags::NO_DECORATION));
|
||||
|
||||
let window = if let Some(glutin_config) = &self.glutin_config {
|
||||
glutin_winit::finalize_window(window_target, window_builder, glutin_config)
|
||||
.map_err(|_| RendererError::GlutinDisplay)?
|
||||
} else {
|
||||
let template_builder = ConfigTemplateBuilder::new();
|
||||
|
||||
let (window, cfg) = DisplayBuilder::new()
|
||||
.with_window_builder(Some(window_builder))
|
||||
.build(window_target, template_builder, |mut configs| {
|
||||
configs.next().unwrap()
|
||||
})
|
||||
.map_err(|_| RendererError::GlutinDisplay)?;
|
||||
|
||||
self.glutin_config = Some(cfg);
|
||||
|
||||
window.unwrap()
|
||||
};
|
||||
|
||||
let glutin_config = self.glutin_config.as_ref().unwrap();
|
||||
|
||||
let context_attribs =
|
||||
ContextAttributesBuilder::new().build(Some(window.raw_window_handle()));
|
||||
let context = unsafe {
|
||||
glutin_config
|
||||
.display()
|
||||
.create_context(&glutin_config, &context_attribs)
|
||||
.map_err(|_| RendererError::GlutinDisplay)?
|
||||
};
|
||||
|
||||
let surface_attribs = SurfaceAttributesBuilder::<WindowSurface>::new().build(
|
||||
window.raw_window_handle(),
|
||||
NonZeroU32::new(viewport.size[0] as u32).unwrap(),
|
||||
NonZeroU32::new(viewport.size[1] as u32).unwrap(),
|
||||
);
|
||||
let surface = unsafe {
|
||||
glutin_config
|
||||
.display()
|
||||
.create_window_surface(glutin_config, &surface_attribs)
|
||||
.map_err(|_| RendererError::GlutinDisplay)?
|
||||
};
|
||||
|
||||
let context = context
|
||||
.make_current(&surface)
|
||||
.map_err(|_| RendererError::GlutinDisplay)?;
|
||||
|
||||
let gl_objects =
|
||||
GlObjects::new(self.font_width, self.font_height, &self.font_pixels, glow)?;
|
||||
|
||||
Ok((
|
||||
window,
|
||||
Some(context.make_not_current().unwrap()),
|
||||
surface,
|
||||
gl_objects,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn render(
|
||||
&mut self,
|
||||
main_window: &Window,
|
||||
glow: &glow::Context,
|
||||
draw_data: &imgui::DrawData,
|
||||
) -> Result<(), RendererError> {
|
||||
Self::render_window(main_window, glow, draw_data, &self.gl_objects)
|
||||
}
|
||||
|
||||
pub fn render_viewports(
|
||||
&mut self,
|
||||
glow: &glow::Context,
|
||||
imgui: &mut imgui::Context,
|
||||
) -> Result<(), RendererError> {
|
||||
for (id, (wnd, context, surface, gl_objects)) in &mut self.extra_windows {
|
||||
if let Some(viewport) = imgui.viewport_by_id(*id) {
|
||||
let current_context = context.take().unwrap().make_current(surface).map_err(|_| RendererError::GlutinDisplay)?;
|
||||
|
||||
unsafe {
|
||||
glow.clear(glow::COLOR_BUFFER_BIT);
|
||||
}
|
||||
Self::render_window(wnd, glow, viewport.draw_data(), gl_objects)?;
|
||||
surface.swap_buffers(¤t_context).map_err(|_| RendererError::GlutinDisplay)?;
|
||||
|
||||
*context = Some(current_context.make_not_current().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn render_window(
|
||||
window: &Window,
|
||||
glow: &glow::Context,
|
||||
draw_data: &imgui::DrawData,
|
||||
gl_objects: &GlObjects,
|
||||
) -> Result<(), RendererError> {
|
||||
unsafe {
|
||||
let window_size = window.inner_size();
|
||||
|
||||
glow.viewport(0, 0, window_size.width as i32, window_size.height as i32);
|
||||
|
||||
glow.bind_vertex_array(Some(gl_objects.vao));
|
||||
glow.bind_buffer(glow::ARRAY_BUFFER, Some(gl_objects.vbo));
|
||||
glow.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(gl_objects.ibo));
|
||||
glow.active_texture(glow::TEXTURE0);
|
||||
glow.bind_texture(glow::TEXTURE_2D, Some(gl_objects.font_texture));
|
||||
glow.use_program(Some(gl_objects.program));
|
||||
|
||||
let left = draw_data.display_pos[0];
|
||||
let right = draw_data.display_pos[0] + draw_data.display_size[0];
|
||||
let top = draw_data.display_pos[1];
|
||||
let bottom = draw_data.display_pos[1] + draw_data.display_size[1];
|
||||
|
||||
|
||||
let matrix = [
|
||||
2.0 / (right - left) , 0.0 , 0.0 , 0.0,
|
||||
0.0 , (2.0 / (top - bottom)) , 0.0 , 0.0,
|
||||
0.0 , 0.0 , -1.0, 0.0,
|
||||
(right + left) / (left - right), (top + bottom) / (bottom - top), 0.0 , 1.0,
|
||||
];
|
||||
|
||||
let loc = glow.get_uniform_location(gl_objects.program, "u_Matrix").unwrap();
|
||||
glow.uniform_matrix_4_f32_slice(Some(&loc), false, &matrix);
|
||||
|
||||
for list in draw_data.draw_lists() {
|
||||
glow.buffer_data_u8_slice(glow::ARRAY_BUFFER, slice::from_raw_parts(list.vtx_buffer().as_ptr().cast(), list.vtx_buffer().len() * 20), glow::STREAM_DRAW);
|
||||
glow.buffer_data_u8_slice(glow::ELEMENT_ARRAY_BUFFER, slice::from_raw_parts(list.idx_buffer().as_ptr().cast(), list.idx_buffer().len() * 2), glow::STREAM_DRAW);
|
||||
|
||||
for cmd in list.commands() {
|
||||
match cmd {
|
||||
imgui::DrawCmd::Elements { count, cmd_params } => {
|
||||
glow.draw_elements_base_vertex(glow::TRIANGLES, count as i32, glow::UNSIGNED_SHORT, (cmd_params.idx_offset * 2) as i32, cmd_params.vtx_offset as i32);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct ViewportData {
|
||||
pos: [f32; 2],
|
||||
size: [f32; 2],
|
||||
focus: bool,
|
||||
minimized: bool,
|
||||
}
|
||||
|
||||
struct PlatformBackend {
|
||||
event_queue: Rc<RefCell<VecDeque<ViewportEvent>>>,
|
||||
}
|
||||
|
||||
impl imgui::PlatformViewportBackend for PlatformBackend {
|
||||
fn create_window(&mut self, viewport: &mut imgui::Viewport) {
|
||||
viewport.platform_user_data = Box::into_raw(Box::new(ViewportData {
|
||||
pos: viewport.pos,
|
||||
size: viewport.size,
|
||||
focus: false,
|
||||
minimized: false,
|
||||
}))
|
||||
.cast();
|
||||
self.event_queue
|
||||
.borrow_mut()
|
||||
.push_back(ViewportEvent::Create(viewport.id));
|
||||
}
|
||||
|
||||
fn destroy_window(&mut self, viewport: &mut imgui::Viewport) {
|
||||
unsafe {
|
||||
drop(Box::from_raw(
|
||||
viewport.platform_user_data.cast::<ViewportData>(),
|
||||
));
|
||||
}
|
||||
viewport.platform_user_data = null_mut();
|
||||
|
||||
self.event_queue
|
||||
.borrow_mut()
|
||||
.push_back(ViewportEvent::Destroy(viewport.id));
|
||||
}
|
||||
|
||||
fn show_window(&mut self, viewport: &mut imgui::Viewport) {
|
||||
self.event_queue
|
||||
.borrow_mut()
|
||||
.push_back(ViewportEvent::SetVisible(viewport.id));
|
||||
}
|
||||
|
||||
fn set_window_pos(&mut self, viewport: &mut imgui::Viewport, pos: [f32; 2]) {
|
||||
self.event_queue
|
||||
.borrow_mut()
|
||||
.push_back(ViewportEvent::SetPos(viewport.id, pos));
|
||||
}
|
||||
|
||||
fn get_window_pos(&mut self, viewport: &mut imgui::Viewport) -> [f32; 2] {
|
||||
unsafe { (*(viewport.platform_user_data.cast::<ViewportData>())).pos }
|
||||
}
|
||||
|
||||
fn set_window_size(&mut self, viewport: &mut imgui::Viewport, size: [f32; 2]) {
|
||||
self.event_queue
|
||||
.borrow_mut()
|
||||
.push_back(ViewportEvent::SetSize(viewport.id, size));
|
||||
}
|
||||
|
||||
fn get_window_size(&mut self, viewport: &mut imgui::Viewport) -> [f32; 2] {
|
||||
unsafe { (*(viewport.platform_user_data.cast::<ViewportData>())).size }
|
||||
}
|
||||
|
||||
fn set_window_focus(&mut self, viewport: &mut imgui::Viewport) {
|
||||
self.event_queue
|
||||
.borrow_mut()
|
||||
.push_back(ViewportEvent::SetFocus(viewport.id));
|
||||
}
|
||||
|
||||
fn get_window_focus(&mut self, viewport: &mut imgui::Viewport) -> bool {
|
||||
unsafe { (*(viewport.platform_user_data.cast::<ViewportData>())).focus }
|
||||
}
|
||||
|
||||
fn get_window_minimized(&mut self, viewport: &mut imgui::Viewport) -> bool {
|
||||
unsafe { (*(viewport.platform_user_data.cast::<ViewportData>())).minimized }
|
||||
}
|
||||
|
||||
fn set_window_title(&mut self, viewport: &mut imgui::Viewport, title: &str) {
|
||||
self.event_queue
|
||||
.borrow_mut()
|
||||
.push_back(ViewportEvent::SetTitle(viewport.id, title.to_owned()));
|
||||
}
|
||||
|
||||
fn set_window_alpha(&mut self, _viewport: &mut imgui::Viewport, _alpha: f32) {}
|
||||
|
||||
fn update_window(&mut self, _viewport: &mut imgui::Viewport) {}
|
||||
|
||||
fn render_window(&mut self, _viewport: &mut imgui::Viewport) {}
|
||||
|
||||
fn swap_buffers(&mut self, _viewport: &mut imgui::Viewport) {}
|
||||
|
||||
fn create_vk_surface(
|
||||
&mut self,
|
||||
_viewport: &mut imgui::Viewport,
|
||||
_instance: u64,
|
||||
_out_surface: &mut u64,
|
||||
) -> i32 {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
struct RendererBackend {}
|
||||
|
||||
impl imgui::RendererViewportBackend for RendererBackend {
|
||||
fn create_window(&mut self, _viewport: &mut imgui::Viewport) {}
|
||||
|
||||
fn destroy_window(&mut self, _viewport: &mut imgui::Viewport) {}
|
||||
|
||||
fn set_window_size(&mut self, _viewport: &mut imgui::Viewport, _size: [f32; 2]) {}
|
||||
|
||||
fn render_window(&mut self, _viewport: &mut imgui::Viewport) {}
|
||||
|
||||
fn swap_buffers(&mut self, _viewport: &mut imgui::Viewport) {}
|
||||
}
|
||||
16
imgui-winit-glow-renderer-viewports/src/vertex_shader.glsl
Normal file
16
imgui-winit-glow-renderer-viewports/src/vertex_shader.glsl
Normal file
@ -0,0 +1,16 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 in_Position;
|
||||
layout(location = 1) in vec2 in_UV;
|
||||
layout(location = 2) in vec4 in_Color;
|
||||
|
||||
uniform mat4 u_Matrix;
|
||||
|
||||
out vec2 v2f_UV;
|
||||
out vec4 v2f_Color;
|
||||
|
||||
void main() {
|
||||
gl_Position = u_Matrix * vec4(in_Position, 0.0, 1.0);
|
||||
v2f_UV = in_UV;
|
||||
v2f_Color = in_Color;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user