Implemented basic viewports renderer

This commit is contained in:
Robin 2022-12-20 13:32:26 +01:00
parent 1d88eceb16
commit 41e9d973f4
2 changed files with 136 additions and 52 deletions

View File

@ -1,4 +1,4 @@
use std::{ffi::CString, num::NonZeroU32}; use std::{ffi::CString, num::NonZeroU32, time::Instant};
use glow::{Context, HasContext}; use glow::{Context, HasContext};
use glutin::{ use glutin::{
@ -12,7 +12,7 @@ use glutin_winit::DisplayBuilder;
use imgui::ConfigFlags; use imgui::ConfigFlags;
use imgui_winit_glow_renderer_viewports::Renderer; use imgui_winit_glow_renderer_viewports::Renderer;
use raw_window_handle::HasRawWindowHandle; use raw_window_handle::HasRawWindowHandle;
use winit::{dpi::LogicalSize, event_loop::EventLoop, window::WindowBuilder}; use winit::{dpi::LogicalSize, event_loop::EventLoop, window::WindowBuilder, event::WindowEvent};
fn main() { fn main() {
let event_loop = EventLoop::new(); let event_loop = EventLoop::new();
@ -74,22 +74,38 @@ fn main() {
.io_mut() .io_mut()
.config_flags .config_flags
.insert(ConfigFlags::VIEWPORTS_ENABLE); .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 renderer = Renderer::new(&mut imgui, &window, &glow).expect("Failed to init Renderer");
let mut last_frame = Instant::now();
event_loop.run(move |event, window_target, control_flow| { event_loop.run(move |event, window_target, control_flow| {
control_flow.set_poll(); control_flow.set_poll();
renderer.handle_event(&mut imgui, &window, &event); renderer.handle_event(&mut imgui, &window, &event);
match event { match event {
winit::event::Event::NewEvents(_) => {
let now = Instant::now();
imgui.io_mut().update_delta_time(now - last_frame);
last_frame = now;
},
winit::event::Event::WindowEvent { window_id, event: WindowEvent::CloseRequested } if window_id == window.id() => {
control_flow.set_exit();
},
winit::event::Event::MainEventsCleared => { winit::event::Event::MainEventsCleared => {
window.request_redraw(); window.request_redraw();
}, },
winit::event::Event::RedrawRequested(_) => { winit::event::Event::RedrawRequested(_) => {
let ui = imgui.frame(); let ui = imgui.frame();
ui.dockspace_over_main_viewport();
ui.show_demo_window(&mut true); ui.show_demo_window(&mut true);
ui.window("Style Editor").build(|| {
ui.show_default_style_editor();
});
ui.end_frame_early(); ui.end_frame_early();
@ -98,9 +114,14 @@ fn main() {
let draw_data = imgui.render(); let draw_data = imgui.render();
context.make_current(&surface).expect("Failed to make current"); if let Err(e) = context.make_current(&surface) {
// For some reason make_current randomly throws errors on windows.
// Until the reason for this is found, we just print it out instead of panicing.
eprintln!("Failed to make current: {e}");
}
unsafe { unsafe {
glow.disable(glow::SCISSOR_TEST);
glow.clear(glow::COLOR_BUFFER_BIT); glow.clear(glow::COLOR_BUFFER_BIT);
} }

View File

@ -3,7 +3,8 @@ use std::{
collections::{HashMap, VecDeque}, collections::{HashMap, VecDeque},
num::NonZeroU32, num::NonZeroU32,
ptr::null_mut, ptr::null_mut,
rc::Rc, slice, rc::Rc,
slice,
}; };
use glow::HasContext; use glow::HasContext;
@ -12,7 +13,7 @@ use glutin::{
context::{ContextAttributesBuilder, NotCurrentContext}, context::{ContextAttributesBuilder, NotCurrentContext},
display::GetGlDisplay, display::GetGlDisplay,
prelude::{GlDisplay, NotCurrentGlContextSurfaceAccessor, PossiblyCurrentGlContext}, prelude::{GlDisplay, NotCurrentGlContextSurfaceAccessor, PossiblyCurrentGlContext},
surface::{Surface, SurfaceAttributesBuilder, WindowSurface, GlSurface}, surface::{GlSurface, Surface, SurfaceAttributesBuilder, WindowSurface},
}; };
use glutin_winit::DisplayBuilder; use glutin_winit::DisplayBuilder;
use imgui::{BackendFlags, Id, Key, ViewportFlags}; use imgui::{BackendFlags, Id, Key, ViewportFlags};
@ -160,22 +161,6 @@ impl GlObjects {
tex 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 { let vbo = unsafe {
glow.create_buffer() glow.create_buffer()
.map_err(|e| RendererError::GlObjectCreationError(e))? .map_err(|e| RendererError::GlObjectCreationError(e))?
@ -185,6 +170,25 @@ impl GlObjects {
.map_err(|e| RendererError::GlObjectCreationError(e))? .map_err(|e| RendererError::GlObjectCreationError(e))?
}; };
let vao = unsafe {
let vao = glow
.create_vertex_array()
.map_err(|e| RendererError::GlObjectCreationError(e))?;
glow.bind_vertex_array(Some(vao));
glow.bind_buffer(glow::ARRAY_BUFFER, Some(vbo));
glow.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(ibo));
glow.enable_vertex_attrib_array(0);
glow.enable_vertex_attrib_array(1);
glow.enable_vertex_attrib_array(2);
glow.vertex_attrib_pointer_f32(0, 2, glow::FLOAT, false, 20, 0);
glow.vertex_attrib_pointer_f32(1, 2, glow::FLOAT, false, 20, 8);
glow.vertex_attrib_pointer_f32(2, 4, glow::UNSIGNED_BYTE, true, 20, 16);
glow.bind_vertex_array(None);
vao
};
Ok(Self { Ok(Self {
program, program,
font_texture, font_texture,
@ -295,7 +299,7 @@ impl Renderer {
gl_objects, gl_objects,
glutin_config: None, glutin_config: None,
extra_windows: HashMap::new(), extra_windows: HashMap::new(),
event_queue: Rc::new(RefCell::new(VecDeque::new())), event_queue,
font_width: font_tex.width, font_width: font_tex.width,
font_height: font_tex.height, font_height: font_tex.height,
font_pixels: font_tex.data.to_vec(), font_pixels: font_tex.data.to_vec(),
@ -313,18 +317,20 @@ impl Renderer {
window_id, window_id,
ref event, ref event,
} => { } => {
let viewport = if window_id == main_window.id() { let (window, viewport) = if window_id == main_window.id() {
imgui.main_viewport_mut() (main_window, imgui.main_viewport_mut())
} else { } else {
if let Some(id) = self.extra_windows.iter().find_map(|(id, (wnd, _, _, _))| { if let Some((id, wnd)) =
if wnd.id() == window_id { self.extra_windows.iter().find_map(|(id, (wnd, _, _, _))| {
Some(*id) if wnd.id() == window_id {
} else { Some((*id, wnd))
None } else {
} None
}) { }
})
{
if let Some(viewport) = imgui.viewport_by_id_mut(id) { if let Some(viewport) = imgui.viewport_by_id_mut(id) {
viewport (wnd, viewport)
} else { } else {
return; return;
} }
@ -335,18 +341,21 @@ impl Renderer {
match *event { match *event {
winit::event::WindowEvent::Resized(new_size) => { winit::event::WindowEvent::Resized(new_size) => {
viewport.size = [new_size.width as f32, new_size.height as f32]; unsafe {
viewport.work_size = viewport.size; (*(viewport.platform_user_data.cast::<ViewportData>())).size =
[new_size.width as f32, new_size.height as f32];
}
if window_id == main_window.id() { if window_id == main_window.id() {
imgui.io_mut().display_size = imgui.io_mut().display_size =
[new_size.width as f32, new_size.height as f32]; [new_size.width as f32, new_size.height as f32];
} }
} }
winit::event::WindowEvent::Moved(new_pos) => { winit::event::WindowEvent::Moved(_) => unsafe {
viewport.pos = [new_pos.x as f32, new_pos.y as f32]; let new_pos = window.inner_position().unwrap().cast::<f32>();
viewport.work_pos = viewport.pos; (*(viewport.platform_user_data.cast::<ViewportData>())).pos =
} [new_pos.x as f32, new_pos.y as f32];
},
winit::event::WindowEvent::CloseRequested if window_id != main_window.id() => { winit::event::WindowEvent::CloseRequested if window_id != main_window.id() => {
viewport.platform_request_close = true; viewport.platform_request_close = true;
} }
@ -368,7 +377,11 @@ impl Renderer {
imgui.io_mut().keys_down[key as usize] = true; imgui.io_mut().keys_down[key as usize] = true;
} }
winit::event::WindowEvent::CursorMoved { position, .. } => { winit::event::WindowEvent::CursorMoved { position, .. } => {
imgui.io_mut().mouse_pos = [position.x as f32, position.y as f32]; let window_pos = window.inner_position().unwrap().cast::<f32>();
imgui.io_mut().mouse_pos = [
position.x as f32 + window_pos.x,
position.y as f32 + window_pos.y,
];
} }
winit::event::WindowEvent::MouseWheel { winit::event::WindowEvent::MouseWheel {
delta, delta,
@ -582,13 +595,20 @@ impl Renderer {
) -> Result<(), RendererError> { ) -> Result<(), RendererError> {
for (id, (wnd, context, surface, gl_objects)) in &mut self.extra_windows { for (id, (wnd, context, surface, gl_objects)) in &mut self.extra_windows {
if let Some(viewport) = imgui.viewport_by_id(*id) { if let Some(viewport) = imgui.viewport_by_id(*id) {
let current_context = context.take().unwrap().make_current(surface).map_err(|_| RendererError::GlutinDisplay)?; let current_context = context
.take()
.unwrap()
.make_current(surface)
.map_err(|_| RendererError::GlutinDisplay)?;
unsafe { unsafe {
glow.disable(glow::SCISSOR_TEST);
glow.clear(glow::COLOR_BUFFER_BIT); glow.clear(glow::COLOR_BUFFER_BIT);
} }
Self::render_window(wnd, glow, viewport.draw_data(), gl_objects)?; Self::render_window(wnd, glow, viewport.draw_data(), gl_objects)?;
surface.swap_buffers(&current_context).map_err(|_| RendererError::GlutinDisplay)?; surface
.swap_buffers(&current_context)
.map_err(|_| RendererError::GlutinDisplay)?;
*context = Some(current_context.make_not_current().unwrap()); *context = Some(current_context.make_not_current().unwrap());
} }
@ -608,6 +628,10 @@ impl Renderer {
glow.viewport(0, 0, window_size.width as i32, window_size.height as i32); glow.viewport(0, 0, window_size.width as i32, window_size.height as i32);
glow.enable(glow::BLEND);
glow.blend_func(glow::SRC_ALPHA, glow::ONE_MINUS_SRC_ALPHA);
glow.enable(glow::SCISSOR_TEST);
glow.bind_vertex_array(Some(gl_objects.vao)); glow.bind_vertex_array(Some(gl_objects.vao));
glow.bind_buffer(glow::ARRAY_BUFFER, Some(gl_objects.vbo)); glow.bind_buffer(glow::ARRAY_BUFFER, Some(gl_objects.vbo));
glow.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(gl_objects.ibo)); glow.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(gl_objects.ibo));
@ -620,27 +644,66 @@ impl Renderer {
let top = draw_data.display_pos[1]; let top = draw_data.display_pos[1];
let bottom = draw_data.display_pos[1] + draw_data.display_size[1]; let bottom = draw_data.display_pos[1] + draw_data.display_size[1];
let matrix = [ let matrix = [
2.0 / (right - left) , 0.0 , 0.0 , 0.0, 2.0 / (right - left),
0.0 , (2.0 / (top - bottom)) , 0.0 , 0.0, 0.0,
0.0 , 0.0 , -1.0, 0.0, 0.0,
(right + left) / (left - right), (top + bottom) / (bottom - top), 0.0 , 1.0, 0.0,
0.0,
(2.0 / (top - bottom)),
0.0,
0.0,
0.0,
0.0,
-1.0,
0.0,
(right + left) / (left - right),
(top + bottom) / (bottom - top),
0.0,
1.0,
]; ];
let loc = glow.get_uniform_location(gl_objects.program, "u_Matrix").unwrap(); let loc = glow
.get_uniform_location(gl_objects.program, "u_Matrix")
.unwrap();
glow.uniform_matrix_4_f32_slice(Some(&loc), false, &matrix); glow.uniform_matrix_4_f32_slice(Some(&loc), false, &matrix);
for list in draw_data.draw_lists() { 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.buffer_data_u8_slice(glow::ELEMENT_ARRAY_BUFFER, slice::from_raw_parts(list.idx_buffer().as_ptr().cast(), list.idx_buffer().len() * 2), glow::STREAM_DRAW); glow::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() { for cmd in list.commands() {
match cmd { match cmd {
imgui::DrawCmd::Elements { count, cmd_params } => { imgui::DrawCmd::Elements { count, cmd_params } => {
glow.draw_elements_base_vertex(glow::TRIANGLES, count as i32, glow::UNSIGNED_SHORT, (cmd_params.idx_offset * 2) as i32, cmd_params.vtx_offset as i32); let clip_x1 = (cmd_params.clip_rect[0] - draw_data.display_pos[0]) as i32;
}, let clip_y1 = (cmd_params.clip_rect[1] - draw_data.display_pos[1]) as i32;
_ => {}, let clip_x2 = (cmd_params.clip_rect[2] - draw_data.display_pos[0]) as i32;
let clip_y2 = (cmd_params.clip_rect[3] - draw_data.display_pos[1]) as i32;
glow.scissor(clip_x1, window_size.height as i32 - clip_y2, clip_x2 - clip_x1, clip_y2 - clip_y1);
glow.draw_elements_base_vertex(
glow::TRIANGLES,
count as i32,
glow::UNSIGNED_SHORT,
(cmd_params.idx_offset * 2) as i32,
cmd_params.vtx_offset as i32,
);
}
_ => {}
} }
} }
} }