From 4a041cc8333093508e309742d5619078326ffc0b Mon Sep 17 00:00:00 2001 From: mitchellhansen Date: Sun, 21 Feb 2021 02:55:43 -0800 Subject: [PATCH] mutzing about with a fps renderer. I am satisfied with this imgui thing I have going on. But it's a bit bone headed to have these two components so tightly coupled --- src/camera.rs | 4 +- src/components.rs | 21 ++++++++++- src/main.rs | 86 ++++++++++++++++++++++++++++++++----------- src/physics/system.rs | 7 +++- src/render/system.rs | 55 ++++++++++++++++++++++----- 5 files changed, 138 insertions(+), 35 deletions(-) diff --git a/src/camera.rs b/src/camera.rs index 36a9a01..afde83c 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -5,7 +5,8 @@ use cgmath::{Decomposed, InnerSpace, Matrix4, Point3, Rad, Vector3}; use winit_24::dpi::{LogicalPosition, PhysicalPosition}; use winit_24::event::{ElementState, MouseScrollDelta, VirtualKeyCode}; use crate::render::OPENGL_TO_WGPU_MATRIX; - +use imgui::Condition; +use imgui::*; #[derive(Clone, Copy, Debug, PartialEq)] pub struct Camera { @@ -150,6 +151,7 @@ impl CameraController { } pub fn update_camera(&mut self, camera: &mut Camera, dt: f32) { + // Move forward/backward and left/right let view_vector = Vector3::new( (1.0 * camera.pitch.0.sin() * camera.yaw.0.sin()), diff --git a/src/components.rs b/src/components.rs index b6891eb..c6af81f 100644 --- a/src/components.rs +++ b/src/components.rs @@ -8,11 +8,13 @@ use rapier3d::geometry::ColliderHandle; use wgpu::{BindGroup, Buffer, TextureView}; use crate::runtime::state::{TomlPositionDescription, TomlRotationDescription}; +use imgui::Ui; // a component is any type that is 'static, sized, send and sync -pub struct ImguiWindow<'a> { - pub window: imgui::Window<'a>, +pub struct ImguiWindow<'a, T> { + pub window: fn() -> imgui::Window<'a>, + pub func: fn(&Ui, &T), } #[derive(Clone, Copy, Debug, PartialEq)] @@ -30,6 +32,21 @@ pub struct Position { pub rot: cgmath::Euler>, } +impl Default for Position { + fn default() -> Self { + Position { + x: 0.0, + y: 0.0, + z: 0.0, + rot: Euler { + x: Deg(0.0), + y: Deg(0.0), + z: Deg(0.0), + }, + } + } +} + impl From for Position { fn from(pos: TomlPositionDescription) -> Self { let euler = match pos.rot { diff --git a/src/main.rs b/src/main.rs index 739664b..ae7d610 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,17 @@ +extern crate env_logger; extern crate imgui; extern crate imgui_wgpu; #[macro_use] extern crate lazy_static; -extern crate tobj; -extern crate winit_24; -extern crate env_logger; -extern crate toml; #[macro_use] extern crate serde_derive; +extern crate tobj; +extern crate toml; +extern crate winit_24; - +use std::collections::HashMap; use std::f32::consts::PI; +use std::fs; use std::sync::{Arc, Mutex}; #[cfg(not(target_arch = "wasm32"))] use std::time::{Duration, Instant}; @@ -20,6 +21,7 @@ use cgmath::{ }; use futures::executor::block_on; use futures::task::LocalSpawn; +use futures::FutureExt; use gilrs::Event as GilEvent; use gilrs::{Gamepad, Gilrs}; use imgui::FontSource; @@ -28,6 +30,7 @@ use imgui::*; use imgui_wgpu::{Renderer as ImguiRenderer, RendererConfig as ImguiRendererConfig}; use legion::systems::{SyncResources, UnsafeResources}; use legion::*; +use log::LevelFilter; use rapier3d::counters::Timer; use rapier3d::dynamics::{ IntegrationParameters, JointSet, RigidBody, RigidBodyBuilder, RigidBodyHandle, RigidBodySet, @@ -40,6 +43,8 @@ use rapier3d::pipeline::PhysicsPipeline; use wgpu::{BindGroup, Buffer, TextureView}; use wgpu_subscriber; use winit_24::event::DeviceEvent::MouseMotion; +use winit_24::event::{ElementState, VirtualKeyCode}; +use winit_24::event_loop::EventLoopProxy; use winit_24::platform::unix::x11::ffi::Time; use winit_24::window::Window; use winit_24::{ @@ -54,13 +59,8 @@ use crate::imgui_supp::extended_winit_imgui_support; use crate::imgui_supp::imgui_support::{ImguiContext, ImguiPlatform}; use crate::owned_event::{OwnedEvent, OwnedEventExtension}; use crate::physics::state::PhysicsState; -use std::fs; -use winit_24::event::{VirtualKeyCode, ElementState}; -use std::collections::HashMap; -use futures::FutureExt; -use log::LevelFilter; +use crate::render::system::ImguiPerformanceProfiler; use crate::runtime::state::RuntimeState; -use winit_24::event_loop::EventLoopProxy; mod camera; mod components; @@ -112,15 +112,16 @@ Todo: //log::info!(""); -// ImGUI works on more or less a global state. which is MegaLame +// ImGUI works on more or less an unsafe global state. which is MegaLame static mut CURRENT_UI: Option> = None; pub unsafe fn current_ui<'a>() -> Option<&'a imgui::Ui<'a>> { CURRENT_UI.as_ref() } fn main() { - - let logger = env_logger::builder().filter(Some("minimal_viable_game_engine"), LevelFilter::Info).init(); + let logger = env_logger::builder() + .filter(Some("minimal_viable_game_engine"), LevelFilter::Info) + .init(); let mut world = World::default(); @@ -134,6 +135,7 @@ fn main() { .build(); let mut render_schedule = Schedule::builder() + .add_system(render::system::render_imgui_system()) .add_system(render::system::render_test_system()) .build(); @@ -156,6 +158,45 @@ fn main() { let mut resources = Resources::default(); + let entity: Entity = world.push(( + ImguiWindow { + // a window that does everything for the performance profiler + window: || { + imgui::Window::new(im_str!("Performance Profiler")) + .size([400.0, 500.0], Condition::FirstUseEver) + .position([50.0, 50.0], Condition::FirstUseEver) + }, + func: |ui: &Ui, a: &ImguiPerformanceProfiler| { + ui.plot_lines(im_str!("blah"), &a.list_of_fps) + .graph_size([200.0, 200.0]) + .scale_min(0.0) + .scale_min(0.01).build(); + ui.text(im_str!("blah blah blah {:?}", a.top_text)); + + let draw_list = ui.get_window_draw_list(); + let o = ui.cursor_screen_pos(); + let ws = ui.content_region_avail(); + a.list_of_fps.iter().fold((0, 0.0f32), |accum, &b| { + let b = b / 10.0; + let x1 = accum.0 as f32 * 1.0 + o[0]; + let x2 = (accum.0 as f32 + 1.0) * 1.0 + o[0]; + let p1 = [x1, accum.1 + o[1]]; + let p2 = [x2, accum.1 + b + o[1]]; + draw_list + .add_line(p1, p2, [128.0,64.0,0.0]) + .thickness(1.0) + .build(); + (accum.0 + 1, b) + }); + }, + }, + ImguiPerformanceProfiler { + top_text: "FPS".to_string(), + list_of_fps: [0.0; 400], + index: 0, + }, + )); + // Load up all the resources { let mut imgui_context = imgui::Context::create(); @@ -242,21 +283,26 @@ fn main() { // conditionally, and run the fps locked renderer event::Event::MainEventsCleared => { event_schedule.execute(&mut world, &mut resources); - imgui_prepare_schedule.execute(&mut world, &mut resources); resources .get_mut::>>() .unwrap() .clear(); + imgui_prepare_schedule.execute(&mut world, &mut resources); + let (step_size, elapsed_time) = { - // deltatime since last frame - let loop_state = resources.get::().unwrap(); + let mut loop_state = resources.get_mut::().unwrap(); ( loop_state.step_size, loop_state.start_time.elapsed().as_secs_f32(), ) }; delta_time = elapsed_time - current_time; + + { + let mut loop_state = resources.get_mut::().unwrap(); + loop_state.delta_time = Duration::from_secs_f32(delta_time); + } current_time = elapsed_time; if delta_time > 0.02 { delta_time = 0.02; @@ -265,10 +311,10 @@ fn main() { while accumulator_time - step_size >= step_size { accumulator_time -= step_size; + // ==== DELTA TIME LOCKED ==== update_schedule.execute(&mut world, &mut resources); } - // ==== FPS LOCKED ==== render_schedule.execute(&mut world, &mut resources); } @@ -297,7 +343,7 @@ fn main() { //d } } - _ => () + _ => (), } } event::Event::WindowEvent { @@ -320,7 +366,6 @@ fn main() { } pub fn setup_gamepad(event_loop: &EventLoop) { - let event_loop_proxy = event_loop.create_proxy(); std::thread::spawn(move || { @@ -362,4 +407,3 @@ pub fn setup_gamepad(event_loop: &EventLoop) { } }); } - diff --git a/src/physics/system.rs b/src/physics/system.rs index 14cc4fc..fd50577 100644 --- a/src/physics/system.rs +++ b/src/physics/system.rs @@ -10,8 +10,9 @@ use rapier3d::geometry::{BroadPhase, ColliderSet, NarrowPhase}; use rapier3d::pipeline::{PhysicsPipeline, ChannelEventCollector}; use crate::camera::{Camera, CameraController}; -use crate::components::{Collider, LoopState, Mesh, Physics, Position}; -use imgui::FontSource; +use crate::components::{Collider, LoopState, Mesh, Physics, Position, ImguiWindow}; +use imgui::{FontSource, Condition}; +use imgui::*; use crate::physics::state::PhysicsState; @@ -73,10 +74,12 @@ pub fn run_physics( } } + #[system] #[write_component(Camera)] #[write_component(CameraController)] pub fn update_camera(world: &mut SubWorld, #[resource] loop_state: &mut LoopState) { + let mut query = <(&mut Camera, &mut CameraController)>::query(); for (mut camera, controller) in query.iter_mut(world) { controller.update_camera(&mut camera, loop_state.step_size) diff --git a/src/render/system.rs b/src/render/system.rs index 9548e49..578962a 100644 --- a/src/render/system.rs +++ b/src/render/system.rs @@ -24,7 +24,7 @@ use winit_24::platform::unix::x11::ffi::Time; use winit_24::window::Window; use crate::camera::{Camera, CameraController}; -use crate::components::{Mesh, Position, RangeCopy}; +use crate::components::{Mesh, Position, RangeCopy, LoopState, ImguiWindow}; use crate::current_ui; use crate::geometry::{load_obj, Vertex}; use crate::imgui_supp::imgui_support::{ImguiContext, ImguiPlatform}; @@ -53,19 +53,64 @@ pub fn imgui_prepare( unsafe { crate::CURRENT_UI = Some(std::mem::transmute(imgui_context.frame())) } } +/// Go through each "global" window-data component and render it's data +#[system] +#[write_component(ImguiWindow)] +#[write_component(ImguiPerformanceProfiler)] +pub fn render_imgui(world: &mut SubWorld, #[resource] loop_state: &mut LoopState) { + + let ui = unsafe { crate::current_ui().unwrap() }; + + let mut query = <(&ImguiPerformanceProfiler, &mut ImguiWindow)>::query(); + for (state, mut window) in query.iter_mut(world) { + let new_window = (window.window)(); + new_window.build(&ui, || { (window.func)(ui, state) }); + + } +} + + +// This would be the shared state for all imgui performance window things +pub struct ImguiPerformanceProfiler { + pub top_text: String, + pub list_of_fps: [f32; 400], + pub index: usize +} + + #[system] #[write_component(Camera)] #[write_component(Position)] +#[write_component(ImguiPerformanceProfiler)] #[write_component(Point3)] #[write_component(Mesh)] #[write_component(DirectionalLight)] pub fn render_test( world: &mut SubWorld, + #[resource] loop_state: &mut LoopState, #[resource] renderer: &mut RenderState, #[resource] winit_window: &mut Window, #[resource] imgui_context: &mut Arc>, #[resource] imgui_platform: &mut Arc>, ) { + + let mut query = <(&mut ImguiPerformanceProfiler)>::query(); + for (mut profiler) in query.iter_mut(world) { + let delta_time = loop_state.delta_time.as_secs_f32(); + let profiler :&mut ImguiPerformanceProfiler = profiler; // trick clion into giving me the type, ugh + + + profiler.top_text = (profiler.list_of_fps.iter().sum::() / profiler.list_of_fps.len() as f32).to_string(); + + profiler.list_of_fps[profiler.index] = 1.0 / delta_time; + + if profiler.index >= 399 { + profiler.index = 0; + } else { + profiler.index += 1; + } + } + let mut encoder = renderer .device .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); @@ -221,16 +266,8 @@ pub fn render_test( let mut imgui_context = &mut imgui_context.lock().unwrap().context; let mut imgui_platform = &mut imgui_platform.lock().unwrap().platform; - //imgui_state.context.io_mut().update_delta_time(Duration::new(0,160)); let ui = unsafe { crate::current_ui().unwrap() }; - let window = imgui::Window::new(im_str!("Hello too")); - window - .size([400.0, 100.0], Condition::FirstUseEver) - .position([50.0, 50.0], Condition::FirstUseEver) - .build(&ui, || { - ui.text(im_str!("Frametime: {:?}", 10.0)); - }); // ui.show_demo_window(&mut true); imgui_platform.prepare_render(&ui, &winit_window);