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

View File

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