From 2370ce4974144701f05eea59709c1235c97252fd Mon Sep 17 00:00:00 2001 From: mitchellhansen Date: Sun, 14 Feb 2021 18:07:26 -0800 Subject: [PATCH] halfway through imgui, the context is really not ergonomic --- Cargo.toml | 7 ++- src/camera.rs | 13 +---- src/geometry.rs | 13 ----- src/main.rs | 147 +++++++++++++++++++++++++++--------------------- src/physics.rs | 14 +++++ src/render.rs | 109 ++++++++++++++++++++++++++++++++++- 6 files changed, 209 insertions(+), 94 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 31e9094..d3185a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ typed-arena = "2.0.1" serde = { version = "1", features = ["derive"], optional = true } log = "0.4" png = "0.16" -winit = { version = "0.22.1", features = ["web-sys"] } +winit = "0.24.0" rand = { version = "0.7.2", features = ["wasm-bindgen"] } bytemuck = "1" noise = "0.6" @@ -29,4 +29,7 @@ cgmath = "0.18.0" rapier3d = { version = "0.5.0", features = ["simd-nightly", "parallel"] } nalgebra = "0.24.1" legion = "0.3.1" -wgpu = "0.7.0" \ No newline at end of file +wgpu = "0.7.0" +imgui = "0.7.0" +imgui-wgpu = "0.14.0" +imgui-winit-support = "0.7.0" \ No newline at end of file diff --git a/src/camera.rs b/src/camera.rs index 493c777..013c050 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -136,16 +136,14 @@ impl CameraController { pub fn update_camera(&mut self, camera: &mut Camera, dt: f32) { // Move forward/backward and left/right - let (yaw_sin, yaw_cos) = camera.yaw.0.sin_cos(); - let forward = Vector3::new(yaw_cos, 0.0, yaw_sin).normalize(); - let right = Vector3::new(-yaw_sin, 0.0, yaw_cos).normalize(); - let view_vector = Vector3::new( (1.0 * camera.pitch.0.sin() * camera.yaw.0.sin()), (1.0 * camera.pitch.0.cos()), (1.0 * camera.pitch.0.sin() * camera.yaw.0.cos()), ); + // Offset the yaw 90 degrees and set the pitch to level for our + // right / left hand translation vectors let offset = camera.yaw.0 + PI/2.0; let pitch = PI/2.0; let left_vector = Vector3::new( @@ -156,19 +154,12 @@ impl CameraController { camera.position += view_vector * (self.amount_forward - self.amount_backward) * self.speed * dt; camera.position += left_vector * (self.amount_left - self.amount_right) * self.speed * dt; - - - // Move up/down. Since we don't use roll, we can just - // modify the y coordinate directly. camera.position.y += (self.amount_up - self.amount_down) * self.speed * dt; // Rotate camera.yaw += Rad(self.rotate_horizontal) * self.sensitivity * dt; camera.pitch += Rad(self.rotate_vertical) * self.sensitivity * dt; - // If process_mouse isn't called every frame, these values - // will not get set to zero, and the camera will rotate - // when moving in a non cardinal direction. self.rotate_horizontal = 0.0; self.rotate_vertical = 0.0; diff --git a/src/geometry.rs b/src/geometry.rs index 573184d..9f9914e 100644 --- a/src/geometry.rs +++ b/src/geometry.rs @@ -61,17 +61,4 @@ pub fn import_mesh(mesh_path: &str) -> (Vec, Vec) { } (vertex_data.to_vec(), index_data.to_vec()) -} - -pub fn create_plane(size: f32) -> (Vec, Vec) { - let vertex_data = [ - vertex([size, -size, 0.0], [0.0, 0.0, 1.0]), - vertex([size, size, 0.0], [0.0, 0.0, 1.0]), - vertex([-size, -size, 0.0], [0.0, 0.0, 1.0]), - vertex([-size, size, 0.0], [0.0, 0.0, 1.0]), - ]; - - let index_data: &[u32] = &[0, 1, 2, 2, 1, 3]; - - (vertex_data.to_vec(), index_data.to_vec()) } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index d60a6ee..8ac4c19 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,6 @@ +extern crate imgui; +extern crate imgui_wgpu; +extern crate imgui_winit_support; extern crate tobj; extern crate winit; @@ -8,9 +11,17 @@ use std::sync::Arc; use std::time::{Duration, Instant}; use bytemuck::__core::ops::Range; -use cgmath::{Decomposed, Deg, Euler, InnerSpace, Quaternion, Rotation3, SquareMatrix, Point3, Rad}; +use cgmath::{ + Decomposed, Deg, Euler, InnerSpace, Point3, Quaternion, Rad, Rotation3, SquareMatrix, +}; +use futures::executor::block_on; use futures::task::LocalSpawn; +use gilrs::{Gamepad, Gilrs}; +use gilrs::Event as GilEvent; +use imgui::*; +use imgui_wgpu::{Renderer as ImguiRenderer, RendererConfig as ImguiRendererConfig}; use legion::*; +use rapier3d::counters::Timer; use rapier3d::dynamics::{ IntegrationParameters, JointSet, RigidBody, RigidBodyBuilder, RigidBodyHandle, RigidBodySet, }; @@ -20,30 +31,27 @@ use rapier3d::na::{Isometry, Isometry3, Vector, Vector3}; use rapier3d::pipeline::PhysicsPipeline; use wgpu::{BindGroup, Buffer, TextureView}; use wgpu_subscriber; -use winit::event::DeviceEvent::MouseMotion; -use winit::platform::unix::x11::ffi::Time; use winit::{ event::{self, WindowEvent}, event_loop::{ControlFlow, EventLoop}, }; +use winit::event::DeviceEvent::MouseMotion; +use winit::platform::unix::x11::ffi::Time; +use winit::window::Window; -use gilrs::Event as GilEvent; - -use crate::camera::{CameraController, Camera}; -use crate::components::{Collider, Color, Physics, Position, LoopState}; +use crate::camera::{Camera, CameraController}; +use crate::components::{Collider, Color, LoopState, Physics, Position}; +use crate::owned_event::{OwnedEvent, OwnedEventExtension}; use crate::physics::PhysicsState; use crate::render::Renderer; -use crate::owned_event::{OwnedEventExtension, OwnedEvent}; -use gilrs::{Gamepad, Gilrs}; -use rapier3d::counters::Timer; mod camera; mod components; mod geometry; mod light; +mod owned_event; mod physics; mod render; -mod owned_event; /* @@ -104,38 +112,36 @@ fn main() { let mut builder = winit::window::WindowBuilder::new(); builder = builder.with_title("MVGE"); - // I don't know what they are doing here - #[cfg(windows_OFF)] // TODO - { - use winit::platform::windows::WindowBuilderExtWindows; - builder = builder.with_no_redirection_bitmap(true); - } - let window = builder.build(&event_loop).unwrap(); - // Load up the renderer (and the resources) - let mut renderer = { - let mut renderer = render::Renderer::init(&window); - entity_loading(&mut world, &mut renderer); - renderer - }; - let mut resources = Resources::default(); - resources.insert(renderer); - let (physics_state, physics_pipeline) = - PhysicsState::build(rapier3d::math::Vector::new(0.0, -9.81, 0.05)); - resources.insert(physics_state); - resources.insert(physics_pipeline); + // Load up all the resources + { - resources.insert(LoopState { - delta_time: Default::default(), - start_time: Instant::now(), - step_size: 0.01666, // 60hz - }); + // The renderer + let mut renderer = render::Renderer::init(&window, &mut imgui_context); + entity_loading(&mut world, &mut renderer); + resources.insert(renderer); + resources.insert(window); + + // Physics + let (physics_state, physics_pipeline) = + PhysicsState::build(rapier3d::math::Vector::new(0.0, -9.81, 0.05)); + resources.insert(physics_state); + resources.insert(physics_pipeline); + // Loop data + resources.insert(LoopState { + delta_time: Default::default(), + start_time: Instant::now(), + step_size: 0.01666, // 60hz + }); - resources.insert(Vec::>::new()); + // And our event stack + resources.insert(Vec::>::new()); + + }; let event_loop_proxy = event_loop.create_proxy(); @@ -147,7 +153,12 @@ fn main() { if gamepad_.name() == "PS4" { gamepad = Some(gamepad_); } - println!("{} is {:?} {:?}", gamepad_.name(), gamepad_.power_info(), gamepad_.id()); + println!( + "{} is {:?} {:?}", + gamepad_.name(), + gamepad_.power_info(), + gamepad_.id() + ); } let mut active_gamepad = None; @@ -155,9 +166,11 @@ fn main() { while let Some(GilEvent { id, event, time }) = gilrs.next_event() { println!("{:?} New event from {}: {:?}", time, id, event); active_gamepad = Some(id); - event_loop_proxy.send_event(OwnedEventExtension::GamepadEvent { - gil_event: GilEvent { id, event, time } - }).ok(); + event_loop_proxy + .send_event(OwnedEventExtension::GamepadEvent { + gil_event: GilEvent { id, event, time }, + }) + .ok(); } // // You can also use cached gamepad state @@ -171,29 +184,35 @@ fn main() { } }); - let mut elapsed_time: f32 = { // deltatime since last frame + let mut elapsed_time: f32 = { + // deltatime since last frame let loop_state = resources.get::().unwrap(); loop_state.start_time.elapsed() - }.as_secs_f32(); + } + .as_secs_f32(); let mut delta_time: f32 = 0.0; let mut accumulator_time: f32 = 0.0; let mut current_time: f32 = elapsed_time; event_loop.run(move |event, _, control_flow| { - *control_flow = ControlFlow::Poll; match event { event::Event::NewEvents(cause) => { event_schedule.execute(&mut world, &mut resources); - resources.get_mut::>>() - .unwrap().clear(); + resources + .get_mut::>>() + .unwrap() + .clear(); } event::Event::MainEventsCleared => { - - let (step_size, elapsed_time) = { // deltatime since last frame + let (step_size, elapsed_time) = { + // deltatime since last frame let loop_state = resources.get::().unwrap(); - (loop_state.step_size, loop_state.start_time.elapsed().as_secs_f32()) + ( + loop_state.step_size, + loop_state.start_time.elapsed().as_secs_f32(), + ) }; delta_time = elapsed_time - current_time; current_time = elapsed_time; @@ -225,9 +244,10 @@ fn main() { .unwrap() .resize(width, height); } - event::Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => { - *control_flow = ControlFlow::Exit - } + event::Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } => *control_flow = ControlFlow::Exit, event::Event::RedrawRequested(_) => { // Call the render system render_schedule.execute(&mut world, &mut resources); @@ -235,11 +255,14 @@ fn main() { _ => {} } - resources.get_mut::>>() - .unwrap().push(event.into()); + resources + .get_mut::>>() + .unwrap() + .push(event.into()); }); } + pub fn entity_loading(world: &mut World, renderer: &mut Renderer) { let monkey_mesh = renderer.load_mesh_to_buffer("./resources/monkey.obj"); @@ -248,10 +271,10 @@ pub fn entity_loading(world: &mut World, renderer: &mut Renderer) { position: Point3 { x: 0.0, y: 0.0, - z: 10.0 + z: 10.0, }, yaw: Rad(-PI), - pitch: Rad(PI/2.0) + pitch: Rad(PI / 2.0), }, Color { r: 1.0, @@ -272,8 +295,8 @@ pub fn entity_loading(world: &mut World, renderer: &mut Renderer) { rot: Euler { x: Deg(0.0), y: Deg(-25.0), - z: Deg(0.0) - } + z: Deg(0.0), + }, }, Color { r: 1.0, @@ -323,17 +346,11 @@ pub fn entity_loading(world: &mut World, renderer: &mut Renderer) { )); let mut dynamic_ball_body = RigidBodyBuilder::new_dynamic() - .position(Isometry3::new( - Vector3::new(0.0, 0.0, 0.0), - Vector::y(), - )) + .position(Isometry3::new(Vector3::new(0.0, 0.0, 0.0), Vector::y())) .build(); let mut static_floor_body = RigidBodyBuilder::new_static() - .position(Isometry3::new( - Vector3::new(0.0, -8.0, 0.0), - Vector::y(), - )) + .position(Isometry3::new(Vector3::new(0.0, -8.0, 0.0), Vector::y())) .build(); let ball_collider = ColliderBuilder::ball(1.5).build(); diff --git a/src/physics.rs b/src/physics.rs index a14954d..62146fe 100644 --- a/src/physics.rs +++ b/src/physics.rs @@ -96,6 +96,20 @@ pub fn update_camera(world: &mut SubWorld, #[resource] loop_state: &mut LoopStat } } +#[system] +#[write_component(Camera)] +pub fn update_imgui( + world: &mut SubWorld, + #[resource] loop_state: &mut LoopState, + #[resource] renderer: &mut Renderer, +) { + + 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) + } +} + #[system] #[write_component(Collider)] #[write_component(Physics)] diff --git a/src/render.rs b/src/render.rs index 9754dc9..0c1c7db 100644 --- a/src/render.rs +++ b/src/render.rs @@ -23,8 +23,12 @@ use winit::window::Window; use crate::camera::{Camera, CameraController}; use crate::components::{Color, Mesh, Position, RangeCopy}; -use crate::geometry::{create_plane, import_mesh, vertex, Vertex}; +use crate::geometry::{import_mesh, vertex, Vertex}; use crate::light::{DirectionalLight, LightRaw}; +use imgui_winit_support::WinitPlatform; +use imgui::*; +use imgui_wgpu::{Renderer as ImguiRenderer, RendererConfig as ImguiRendererConfig}; +use std::cell::RefCell; #[cfg_attr(rustfmt, rustfmt_skip)] #[allow(unused)] @@ -80,7 +84,12 @@ pub struct Pass { #[write_component(Mesh)] #[write_component(Color)] #[write_component(DirectionalLight)] -pub fn render_test(world: &mut SubWorld, #[resource] renderer: &mut Renderer) { +pub fn render_test( + world: &mut SubWorld, + #[resource] renderer: &mut Renderer, + #[resource] winit_window: &mut Window, +) { + let mut encoder = renderer .device .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); @@ -88,6 +97,92 @@ pub fn render_test(world: &mut SubWorld, #[resource] renderer: &mut Renderer) { let frame = renderer.get_current_frame(); + + // set up imgui for rendering + + // update delta time and prepare the frame + //renderer.imgui_platform.io_mut().update_delta_time(now - last_frame); + + { + + let mut imgui_context = imgui::Context::create(); + imgui_context.set_ini_filename(None); + + let font_size = 10.0 as f32; + //imgui_context.io_mut().font_global_scale = 10.0 as f32; + + imgui_context.fonts().add_font(&[FontSource::DefaultFontData { + config: Some(imgui::FontConfig { + oversample_h: 1, + pixel_snap_h: true, + size_pixels: font_size, + ..Default::default() + }), + }]); + + // The imgui context lives as a resource for the render system to use + let mut platform = imgui_winit_support::WinitPlatform::init(imgui_context); + platform.attach_window( + imgui_context.io_mut(), + window, + imgui_winit_support::HiDpiMode::Default, + ); + + let clear_color = wgpu::Color { + r: 0.1, + g: 0.2, + b: 0.3, + a: 1.0, + }; + + let renderer_config = ImguiRendererConfig { + texture_format: sc_desc.format, + ..Default::default() + }; + + let mut renderer = ImguiRenderer::new(imgui_context, &device, &queue, renderer_config); + + renderer.imgui_platform + .prepare_frame(imgui_context.io_mut(), &winit_window) + .expect("Failed to prepare frame"); + + // get the frame and build a ui window + let ui = imgui_context.frame(); + let window = imgui::Window::new(im_str!("Hello too")); + window + .size([400.0, 200.0], Condition::FirstUseEver) + .position([400.0, 200.0], Condition::FirstUseEver) + .build(&ui, || { + ui.text(im_str!("Frametime: {:?}", 10.0)); + }); + + + //ui.show_demo_window(&mut demo_open); + renderer.imgui_platform.prepare_render(&ui, &winit_window); + + let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: None, + color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { + attachment: &frame.output.view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color { + r: 0.1, + g: 0.2, + b: 0.3, + a: 1.0, + }), + store: true, + }, + }], + depth_stencil_attachment: None, + }); + renderer.imgui_renderer + .render(ui.render(), &renderer.queue, &renderer.device, &mut rpass) + .expect("Rendering failed"); + + drop(rpass); + } // Update the camera uniform buffers, need to make it support selection of // cameras let mut query = <(&mut Camera)>::query(); @@ -253,6 +348,10 @@ pub struct Renderer { light_uniform_buf: wgpu::Buffer, camera_projection: Matrix4, + + imgui_platform: WinitPlatform, + imgui_renderer: ImguiRenderer, + } impl Renderer { @@ -393,7 +492,8 @@ impl Renderer { } } - pub fn init(window: &Window) -> Renderer { + pub fn init(window: &Window, imgui_context: &mut imgui::Context) -> Renderer { + // Grab the GPU instance, and query its features let instance = wgpu::Instance::new(wgpu::BackendBit::PRIMARY); let (size, surface) = unsafe { @@ -804,6 +904,7 @@ impl Renderer { label: Some("Depth Texture"), }); + Renderer { swapchain: swap_chain, queue: queue, @@ -821,6 +922,8 @@ impl Renderer { instance: Arc::new(instance), views_given: 0, camera_projection: mx_projection, + imgui_platform: platform, + imgui_renderer: renderer } }