From 4e4725d1ac69a8f747576303a01dd209f69218e1 Mon Sep 17 00:00:00 2001 From: Ben Wallis Date: Sat, 25 Jul 2020 18:08:35 +0100 Subject: [PATCH] initial imgui implementation --- Cargo.lock | 54 +++++++++++++++++++++++++++++++--- server-cli/Cargo.toml | 2 +- server-cli/src/main.rs | 5 +++- voxygen/Cargo.toml | 4 +++ voxygen/src/main.rs | 3 ++ voxygen/src/render/renderer.rs | 50 +++++++++++++++++++++++++++++-- voxygen/src/run.rs | 9 +++++- voxygen/src/window.rs | 47 +++++++++++++++++++++++++++-- 8 files changed, 162 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8b3401d012..cf9ae10446 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,9 +71,9 @@ checksum = "b8052e2d8aabbb8d556d6abbcce2a22b9590996c5f849b9c7ce4544a2e3b984e" [[package]] name = "ansi_term" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" dependencies = [ "winapi 0.3.8", ] @@ -2053,6 +2053,49 @@ dependencies = [ "png", ] +[[package]] +name = "imgui" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fdb2bcc7e498e78137ce28705ae836d69e36ee2eac89d0d926cfabfcf550570" +dependencies = [ + "bitflags", + "gfx", + "imgui-sys", + "lazy_static", + "parking_lot 0.10.2", +] + +[[package]] +name = "imgui-gfx-renderer" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1865f465732ee450bcc8d1c45576b3099955caec163cee82318da763eb22df94" +dependencies = [ + "gfx", + "imgui", + "winapi 0.3.8", +] + +[[package]] +name = "imgui-sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72be9671d64dd0ed26bb708cd10060a431262ac90ae70cf7c5912feefe6849da" +dependencies = [ + "cc", +] + +[[package]] +name = "imgui-winit-support" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98171c35263e3eb0dfb66cb876e3efdb788d777c1b613c7d2592303d1276bb5" +dependencies = [ + "imgui", + "winit", +] + [[package]] name = "indexmap" version = "1.4.0" @@ -4319,9 +4362,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.2.6" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04a11b459109e38ff6e1b580bafef4142a11d44889f5d07424cbce2fd2a2a119" +checksum = "e4f5dd7095c2481b7b3cbed71c8de53085fb3542bc3c2b4c73cba43e8f11c7ba" dependencies = [ "ansi_term", "chrono", @@ -4636,6 +4679,9 @@ dependencies = [ "guillotiere", "hashbrown", "image", + "imgui", + "imgui-gfx-renderer", + "imgui-winit-support", "msgbox", "num 0.2.1", "old_school_gfx_glutin_ext", diff --git a/server-cli/Cargo.toml b/server-cli/Cargo.toml index 96d761b3e3..c57f7e0469 100644 --- a/server-cli/Cargo.toml +++ b/server-cli/Cargo.toml @@ -13,4 +13,4 @@ server = { package = "veloren-server", path = "../server", default-features = fa common = { package = "veloren-common", path = "../common" } tracing = { version = "0.1", default-features = false } -tracing-subscriber = { version = "0.2.3", default-features = false, features = ["env-filter", "fmt", "chrono", "ansi", "smallvec"] } +tracing-subscriber = { version = "0.2.9", default-features = false, features = ["env-filter", "fmt", "chrono", "ansi", "smallvec"] } diff --git a/server-cli/src/main.rs b/server-cli/src/main.rs index 3668f8c97a..d824cb5ca0 100644 --- a/server-cli/src/main.rs +++ b/server-cli/src/main.rs @@ -18,7 +18,10 @@ fn main() { .add_directive(LevelFilter::INFO.into()); for s in env.split(',').into_iter() { match s.parse() { - Ok(d) => filter = filter.add_directive(d), + Ok(d) => { + println!("Adding filter directive: {}", d); + filter = filter.add_directive(d); + }, Err(err) => println!("WARN ignoring log directive: `{}`: {}", s, err), }; } diff --git a/voxygen/Cargo.toml b/voxygen/Cargo.toml index 7576819aed..5cea510617 100644 --- a/voxygen/Cargo.toml +++ b/voxygen/Cargo.toml @@ -32,6 +32,10 @@ conrod_core = { git = "https://gitlab.com/veloren/conrod.git" } conrod_winit = { git = "https://gitlab.com/veloren/conrod.git" } euc = { git = "https://github.com/zesterer/euc.git" } +imgui = "0.4.0" +imgui-gfx-renderer = "0.4.0" +imgui-winit-support = "0.4.0" + # ECS specs = { git = "https://github.com/amethyst/specs.git", rev = "7a2e348ab2223818bad487695c66c43db88050a5" } specs-idvs = { git = "https://gitlab.com/veloren/specs-idvs.git", branch = "specs-git" } diff --git a/voxygen/src/main.rs b/voxygen/src/main.rs index d119fdb788..f097e0c152 100644 --- a/voxygen/src/main.rs +++ b/voxygen/src/main.rs @@ -3,6 +3,9 @@ #![feature(bool_to_option)] #![recursion_limit = "2048"] +#[macro_use] +extern crate imgui; + use veloren_voxygen::{ audio::{self, AudioFrontend}, i18n::{self, i18n_asset_key, VoxygenLocalization}, diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index a6e37ff192..3587e4beb9 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -18,6 +18,10 @@ use gfx::{ use glsl_include::Context as IncludeContext; use tracing::error; use vek::*; +use imgui::{DrawData, Context, im_str, Window, Condition, ConfigFlags}; +use imgui_winit_support::WinitPlatform; +use winit::event::Event; +use imgui::sys::ImGuiConfigFlags_NoMouseCursorChange; /// Represents the format of the pre-processed color target. pub type TgtColorFmt = gfx::format::Srgba8; @@ -52,10 +56,10 @@ pub type TgtColorRes = gfx::handle::ShaderResourceView< /// kinds of models to the screen. pub struct Renderer { device: gfx_backend::Device, - encoder: gfx::Encoder, - factory: gfx_backend::Factory, + pub encoder: gfx::Encoder, + pub factory: gfx_backend::Factory, - win_color_view: WinColorView, + pub win_color_view: WinColorView, win_depth_view: WinDepthView, tgt_color_view: TgtColorView, @@ -81,6 +85,9 @@ pub struct Renderer { aa_mode: AaMode, cloud_mode: CloudMode, fluid_mode: FluidMode, + pub imgui: Context, + pub imgui_platform: WinitPlatform, + pub imgui_renderer: imgui_gfx_renderer::Renderer } impl Renderer { @@ -94,6 +101,9 @@ impl Renderer { aa_mode: AaMode, cloud_mode: CloudMode, fluid_mode: FluidMode, + imgui: Context, + imgui_platform: WinitPlatform, + imgui_renderer: imgui_gfx_renderer::Renderer ) -> Result { let mut shader_reload_indicator = ReloadIndicator::new(); @@ -157,9 +167,43 @@ impl Renderer { aa_mode, cloud_mode, fluid_mode, + imgui, + imgui_platform, + imgui_renderer }) } + pub fn render_imgui(&mut self, window: &winit::window::Window) { + self.imgui_platform + .prepare_frame(self.imgui.io_mut(), window) + .expect("Failed to start frame"); + + self.imgui.io_mut().config_flags |= ConfigFlags::NO_MOUSE_CURSOR_CHANGE; + + let ui = self.imgui.frame(); + Window::new(im_str!("Test")) + .size([1000.0, 300.0], Condition::FirstUseEver) + .build(&ui, || { + ui.text(im_str!("Hello world!")); + ui.text(im_str!("こんにちは世界!")); + ui.text(im_str!("This...is...imgui-rs!")); + ui.separator(); + let mouse_pos = ui.io().mouse_pos; + ui.text(format!( + "Mouse Position: ({:.1},{:.1})", + mouse_pos[0], mouse_pos[1] + )); + }); + self.imgui_platform.prepare_render(&ui, &window); + let draw_data = ui.render(); + self.imgui_renderer.render(&mut self.factory, &mut self.encoder, &mut self.win_color_view, draw_data) + .expect("imgui rendering failed"); + } + + pub fn handle_imgui_events(&mut self, window: &winit::window::Window, event: &Event<()>) { + self.imgui_platform.handle_event(self.imgui.io_mut(), window, event); + } + /// Get references to the internal render target views that get rendered to /// before post-processing. #[allow(dead_code)] diff --git a/voxygen/src/run.rs b/voxygen/src/run.rs index b738aeb511..bb458039b7 100644 --- a/voxygen/src/run.rs +++ b/voxygen/src/run.rs @@ -26,6 +26,8 @@ pub fn run(mut global_state: GlobalState, event_loop: EventLoop) { // Continously run loop since we handle sleeping *control_flow = winit::event_loop::ControlFlow::Poll; + global_state.window.handle_imgui_events(&event); + // Get events for the ui. if let Some(event) = ui::Event::try_from(&event, global_state.window.window()) { global_state.window.send_event(Event::Ui(event)); @@ -138,8 +140,13 @@ fn handle_main_events_cleared( if let Some(last) = states.last_mut() { global_state.window.renderer_mut().clear(); + + // Render the game last.render(global_state.window.renderer_mut(), &global_state.settings); - // Finish the frame. + + // Render imgui on top + global_state.window.render_imgui(); + global_state.window.renderer_mut().flush(); global_state .window diff --git a/voxygen/src/window.rs b/voxygen/src/window.rs index 68a536a8ab..4e5089691f 100644 --- a/voxygen/src/window.rs +++ b/voxygen/src/window.rs @@ -12,6 +12,9 @@ use serde_derive::{Deserialize, Serialize}; use std::fmt; use tracing::{error, info, warn}; use vek::*; +use imgui_winit_support::{WinitPlatform, HiDpiMode}; +use imgui::{Context, FontSource, FontConfig, FontGlyphRanges}; +use imgui_gfx_renderer::Shaders; /// Represents a key that the game recognises after input mapping. #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)] @@ -490,7 +493,7 @@ pub struct Window { message_receiver: channel::Receiver, // Used for screenshots & fullscreen toggle to deduplicate/postpone to after event handler take_screenshot: bool, - toggle_fullscreen: bool, + toggle_fullscreen: bool } impl Window { @@ -512,7 +515,7 @@ impl Window { false, ); - let (window, device, factory, win_color_view, win_depth_view) = + let (window, device, mut factory, win_color_view, win_depth_view) = glutin::ContextBuilder::new() .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2))) .with_vsync(false) @@ -521,6 +524,35 @@ impl Window { .map_err(|err| Error::BackendError(Box::new(err)))? .init_gfx::(); + let mut imgui = Context::create(); + + imgui.set_ini_filename(None); + let mut imgui_winit_platform = WinitPlatform::init(&mut imgui); + imgui_winit_platform.attach_window(imgui.io_mut(), window.window(), HiDpiMode::Rounded); + let hidpi_factor = imgui_winit_platform.hidpi_factor(); + let font_size = (13.0 * hidpi_factor) as f32; + imgui.fonts().add_font(&[ + FontSource::DefaultFontData { + config: Some(FontConfig { + size_pixels: font_size, + ..FontConfig::default() + }), + }, + FontSource::TtfData { + data: include_bytes!("resources/mplus-1p-regular.ttf"), + size_pixels: font_size, + config: Some(FontConfig { + rasterizer_multiply: 1.75, + glyph_ranges: FontGlyphRanges::japanese(), + ..FontConfig::default() + }), + }, + ]); + + imgui.io_mut().font_global_scale = (1.0 / hidpi_factor) as f32; + let imgui_renderer = imgui_gfx_renderer::Renderer::init(&mut imgui, &mut factory, Shaders::GlSl150) + .expect("Failed to initialize renderer"); + let vendor = device.get_info().platform_name.vendor; let renderer = device.get_info().platform_name.renderer; let opengl_version = device.get_info().version; @@ -573,6 +605,9 @@ impl Window { settings.graphics.aa_mode, settings.graphics.cloud_mode, settings.graphics.fluid_mode, + imgui, + imgui_winit_platform, + imgui_renderer )?, window, cursor_grabbed: false, @@ -613,6 +648,10 @@ impl Window { pub fn renderer_mut(&mut self) -> &mut Renderer { &mut self.renderer } + pub fn render_imgui(&mut self) { + self.renderer.render_imgui(&self.window.window()); + } + pub fn resolve_deduplicated_events(&mut self, settings: &mut Settings) { // Handle screenshots and toggling fullscreen if self.take_screenshot { @@ -1094,6 +1133,10 @@ impl Window { pub fn send_event(&mut self, event: Event) { self.events.push(event) } + pub fn handle_imgui_events(&mut self, event: &winit::event::Event<()>) { + self.renderer.handle_imgui_events(self.window.window(), event); + } + pub fn take_screenshot(&mut self, settings: &Settings) { match self.renderer.create_screenshot() { Ok(img) => {