Flesh out examples

This commit is contained in:
John-Mark Allen 2021-06-09 23:03:09 +01:00 committed by Jack Spira
parent 06b08508d9
commit f1bd13b73e
4 changed files with 296 additions and 3 deletions

View File

@ -1,8 +1,6 @@
//! A basic self-contained example to get you from zero-to-demo-window as fast
//! as possible.
use std::time::Instant;
use glow::HasContext;
use glutin::{event_loop::EventLoop, WindowedContext};
use imgui_winit_support::WinitPlatform;
@ -26,7 +24,6 @@ fn main() {
.expect("failed to create renderer");
// Standard winit event loop
let mut last_frame = Instant::now();
event_loop.run(move |event, _, control_flow| {
*control_flow = glutin::event_loop::ControlFlow::Wait;
match event {

View File

@ -0,0 +1,82 @@
//! A basic example showing imgui rendering together with some custom rendering.
//!
//! Note this example uses `RendererBuilder` rather than `auto_renderer` and
//! (because we're using the default "trivial" `ContextStateManager`)
//! therefore does not attempt to backup/restore OpenGL state.
use std::time::Instant;
use glow::HasContext;
mod utils;
use utils::Triangler;
fn main() {
let (event_loop, window) = utils::create_window("Hello, triangle!", glutin::GlRequest::Latest);
let (mut winit_platform, mut imgui_context) = utils::imgui_init(&window);
let gl = utils::glow_context(&window);
let mut ig_renderer = imgui_glow_renderer::RendererBuilder::new()
.build_owning(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, _, control_flow| {
*control_flow = glutin::event_loop::ControlFlow::Wait;
match event {
glutin::event::Event::NewEvents(_) => {
let now = Instant::now();
imgui_context
.io_mut()
.update_delta_time(now.duration_since(last_frame));
last_frame = now;
}
glutin::event::Event::MainEventsCleared => {
winit_platform
.prepare_frame(imgui_context.io_mut(), window.window())
.unwrap();
window.window().request_redraw();
}
glutin::event::Event::RedrawRequested(_) => {
{
let gl = ig_renderer.gl_context();
// This is required because, without the `StateBackupCsm`
// (which is provided by `auto_renderer` but not
// `RendererBuilder` by default), the OpenGL context is left
// in an arbitrary, dirty state
unsafe { gl.disable(glow::SCISSOR_TEST) };
tri_renderer.render(gl);
}
let ui = imgui_context.frame();
// Safety: internally, this reference just gets passed as a
// pointer to imgui, which handles the null pointer properly.
ui.show_demo_window(unsafe { &mut *std::ptr::null_mut() });
winit_platform.prepare_render(&ui, window.window());
let draw_data = ui.render();
ig_renderer
.render(&draw_data)
.expect("error rendering imgui");
window.swap_buffers().unwrap();
}
glutin::event::Event::WindowEvent {
event: glutin::event::WindowEvent::CloseRequested,
..
} => {
*control_flow = glutin::event_loop::ControlFlow::Exit;
}
glutin::event::Event::LoopDestroyed => {
let gl = ig_renderer.gl_context();
tri_renderer.destroy(gl);
}
event => {
winit_platform.handle_event(imgui_context.io_mut(), window.window(), &event);
}
}
});
}

View File

@ -0,0 +1,79 @@
//! A basic example showing imgui rendering together with some custom rendering
//! using OpenGL ES, rather than full-fat OpenGL.
//!
//! Note this example uses `Renderer` rather than `OwningRenderer` and
//! therefore requries more lifetime-management of the OpenGL context.
use std::time::Instant;
mod utils;
use utils::Triangler;
fn main() {
let (event_loop, window) = utils::create_window(
"Hello, triangle!",
glutin::GlRequest::Specific(glutin::Api::OpenGlEs, (3, 0)),
);
let (mut winit_platform, mut imgui_context) = utils::imgui_init(&window);
let gl = utils::glow_context(&window);
let mut ig_renderer = imgui_glow_renderer::RendererBuilder::new()
.with_context_state_manager(imgui_glow_renderer::StateBackupCsm::default())
.build_borrowing(&gl, &mut imgui_context)
.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, _, control_flow| {
*control_flow = glutin::event_loop::ControlFlow::Wait;
match event {
glutin::event::Event::NewEvents(_) => {
let now = Instant::now();
imgui_context
.io_mut()
.update_delta_time(now.duration_since(last_frame));
last_frame = now;
}
glutin::event::Event::MainEventsCleared => {
winit_platform
.prepare_frame(imgui_context.io_mut(), window.window())
.unwrap();
window.window().request_redraw();
}
glutin::event::Event::RedrawRequested(_) => {
tri_renderer.render(&gl);
let ui = imgui_context.frame();
// Safety: internally, this reference just gets passed as a
// pointer to imgui, which handles the null pointer properly.
ui.show_demo_window(unsafe { &mut *std::ptr::null_mut() });
winit_platform.prepare_render(&ui, window.window());
let draw_data = ui.render();
ig_renderer
.render(&gl, &draw_data)
.expect("error rendering imgui");
window.swap_buffers().unwrap();
}
glutin::event::Event::WindowEvent {
event: glutin::event::WindowEvent::CloseRequested,
..
} => {
*control_flow = glutin::event_loop::ControlFlow::Exit;
}
glutin::event::Event::LoopDestroyed => {
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.window(), &event);
}
}
});
}

View File

@ -0,0 +1,135 @@
use glow::HasContext;
use glutin::{event_loop::EventLoop, GlRequest};
use imgui_winit_support::WinitPlatform;
pub type Window = glutin::WindowedContext<glutin::PossiblyCurrent>;
pub fn create_window(title: &str, gl_request: GlRequest) -> (EventLoop<()>, Window) {
let event_loop = glutin::event_loop::EventLoop::new();
let window = glutin::window::WindowBuilder::new()
.with_title(title)
.with_inner_size(glutin::dpi::LogicalSize::new(1024, 768));
let window = glutin::ContextBuilder::new()
.with_gl(gl_request)
.with_vsync(true)
.build_windowed(window, &event_loop)
.expect("could not create window");
let window = unsafe {
window
.make_current()
.expect("could not make window context current")
};
(event_loop, window)
}
pub fn glow_context(window: &Window) -> glow::Context {
unsafe { glow::Context::from_loader_function(|s| window.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.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;
void main() {
vert = verts[gl_VertexID];
gl_Position = vec4(vert - 0.5, 0.0, 1.0);
}
"#;
const FRAGMENT_SHADER_SOURCE: &str = r#"
in vec2 vert;
out vec4 colour;
void main() {
colour = vec4(vert, 0.5, 1.0);
}
"#;
let mut shaders = [
(glow::VERTEX_SHADER, VERTEX_SHADER_SOURCE, 0),
(glow::FRAGMENT_SHADER, FRAGMENT_SHADER_SOURCE, 0),
];
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 = 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);
gl.delete_shader(shader);
}
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);
}
}
}