diff --git a/src/graphics.rs b/src/graphics.rs index b5abe05..448914f 100644 --- a/src/graphics.rs +++ b/src/graphics.rs @@ -8,12 +8,6 @@ pub struct ModelUpdate{ color:Option, } -#[derive(Clone)] -pub enum GraphicsInstruction{ - UpdateModel(ModelUpdate), - Render, -} - struct Entity { index_count: u32, index_buf: wgpu::Buffer, @@ -878,31 +872,27 @@ impl GraphicsState{ device:&wgpu::Device, queue:&wgpu::Queue, config:&wgpu::SurfaceConfiguration, + user_settings:&crate::settings::UserSettings, ) { self.depth_view = Self::create_depth_texture(config,device); self.camera.screen_size=glam::uvec2(config.width, config.height); - self.load_user_settings(&self.user_settings); + self.load_user_settings(user_settings); } pub fn render( &mut self, - view: &wgpu::TextureView, - device: &wgpu::Device, - queue: &wgpu::Queue, + view:&wgpu::TextureView, + device:&wgpu::Device, + queue:&wgpu::Queue, + predicted_time:crate::integer::Time, + physics_output:crate::physics::PhysicsOutputState, ) { - //ideally this would be scheduled to execute and finish right before the render. - let time=crate::integer::Time::from_nanos(self.start_time.elapsed().as_nanos() as i64); - self.physics_thread.send(crate::instruction::TimedInstruction{ - time, - instruction:crate::render_thread::InputInstruction::Idle, - }).unwrap(); - //update time lol - self.mouse.time=time; + //TODO: use scheduled frame times to create beautiful smoothing simulation physics extrapolation assuming no input let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); // update rotation - let camera_uniforms = self.camera.to_uniform_data(self.physics_thread.grab_clone().adjust_mouse(&self.mouse)); + let camera_uniforms = self.camera.to_uniform_data(physics_output.extrapolate(self.global_mouse.lock().clone(),predicted_time)); self.staging_belt .write_buffer( &mut encoder, diff --git a/src/graphics_context.rs b/src/graphics_context.rs deleted file mode 100644 index c3a9f1e..0000000 --- a/src/graphics_context.rs +++ /dev/null @@ -1,13 +0,0 @@ -struct Context<'a>{ - device:&'a wgpu::Device, - queue:&'a wgpu::Queue, -} - -impl Context{ - pub fn new(user_settings:&crate::settings::UserSettings,indexed_model_instances:&crate::model::IndexedModelInstances){ - let mut graphics=crate::graphics::GraphicsState::new(); - graphics.load_user_settings(user_settings); - graphics.generate_models(indexed_model_instances); - } - //into_worker -} \ No newline at end of file diff --git a/src/graphics_worker.rs b/src/graphics_worker.rs new file mode 100644 index 0000000..6a2dd3c --- /dev/null +++ b/src/graphics_worker.rs @@ -0,0 +1,46 @@ +#[derive(Clone)] +pub enum GraphicsInstruction{ + Render(crate::physics::PhysicsOutputState,crate::integer::Time), + //UpdateModel(crate::graphics::ModelUpdate), +} + +//Ideally the graphics thread worker description is: +/* +WorkerDescription{ + input:Immediate, + output:Realtime(PoolOrdering::Ordered(3)), +} +*/ +//up to three frames in flight, dropping new frame requests when all three are busy, and dropping output frames when one renders out of order + +pub fn new( + graphics:crate::graphics::GraphicsState, + surface:&wgpu::Surface, + device:&wgpu::Device, + queue:&wgpu::Queue, + )->crate::worker::INWorker{ + crate::worker::INWorker::new(a,move |ins:GraphicsInstruction|{ + match ins{ + GraphicsInstruction::Render(physics_output,predicted_time)=>{ + //this has to go deeper somehow + let frame=match surface.get_current_texture(){ + Ok(frame)=>frame, + Err(_)=>{ + surface.configure(device,config); + surface + .get_current_texture() + .expect("Failed to acquire next surface texture!") + } + }; + let view=frame.texture.create_view(&wgpu::TextureViewDescriptor{ + format:Some(config.view_formats[0]), + ..wgpu::TextureViewDescriptor::default() + }); + + graphics.render(&view,device,queue,physics_output,predicted_time); + + frame.present(); + } + } + }) +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index e6ef0b4..d36476b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,8 +13,8 @@ mod primitives; mod instruction; mod load_roblox; mod model_graphics; -mod physics_context; -mod graphics_context; +mod physics_worker; +mod graphics_worker; fn load_file(path: std::path::PathBuf)->Option{ println!("Loading file: {:?}", &path); diff --git a/src/physics.rs b/src/physics.rs index 1f6cddf..ec32cad 100644 --- a/src/physics.rs +++ b/src/physics.rs @@ -533,8 +533,8 @@ pub struct PhysicsOutputState{ body:Body, } impl PhysicsOutputState{ - pub fn adjust_mouse(&self,mouse:&MouseState)->(glam::Vec3,glam::Vec2){ - ((self.body.extrapolated_position(mouse.time)+self.camera.offset).into(),self.camera.simulate_move_angles(mouse.pos)) + pub fn extrapolate(&self,mouse_pos:glam::IVec2,time:Time)->(glam::Vec3,glam::Vec2){ + ((self.body.extrapolated_position(time)+self.camera.offset).into(),self.camera.simulate_move_angles(mouse_pos)) } } diff --git a/src/physics_context.rs b/src/physics_worker.rs similarity index 73% rename from src/physics_context.rs rename to src/physics_worker.rs index 1ea9c0d..08b5307 100644 --- a/src/physics_context.rs +++ b/src/physics_worker.rs @@ -20,29 +20,9 @@ pub enum InputInstruction { //to be 1 instruction ahead to generate the next state for interpolation. } -pub struct Context{ - //Ideally the graphics thread worker description is: - /* - WorkerDescription{ - input:Immediate, - output:Realtime(PoolOrdering::Ordered(3)), - } - */ - //up to three frames in flight, dropping new frame requests when all three are busy, and dropping output frames when one renders out of order - graphics_thread:crate::worker::INWorker, -} -impl Context{ - pub fn new(user_settings:&crate::settings::UserSettings,indexed_model_instances:&crate::model::IndexedModelInstances){ - let mut physics=crate::physics::PhysicsState::default(); - physics.spawn(indexed_model_instances.spawn_point); - physics.load_user_settings(user_settings); - physics.generate_models(&indexed_model_instances); - } - pub fn into_worker(mut self)->crate::worker::QNWorker>{ - let graphics_context=crate::graphics_context::Context::new(); - let graphics_thread=graphics_context.into_worker(); + pub fn new(physics:crate::physics::PhysicsState,graphics_worker:crate::worker::INWorker)->crate::worker::QNWorker>{ let mut mouse_blocking=true; - let mut last_mouse_time=self.physics.next_mouse.time; + let mut last_mouse_time=physics.next_mouse.time; let mut timeline=std::collections::VecDeque::new(); crate::worker::QNWorker::new(move |ins:TimedInstruction|{ let mut render=false; @@ -60,7 +40,7 @@ impl Context{ timeline.push_front(TimedInstruction{ time:last_mouse_time, instruction:PhysicsInputInstruction::ReplaceMouse( - MouseState{time:last_mouse_time,pos:self.physics.next_mouse.pos}, + MouseState{time:last_mouse_time,pos:physics.next_mouse.pos}, MouseState{time:ins.time,pos:m} ), }); @@ -92,11 +72,11 @@ impl Context{ //shitty mice are 125Hz which is 8ms so this should cover that. //setting this to 100us still doesn't print even though it's 10x lower than the polling rate, //so mouse events are probably not handled separately from drawing and fire right before it :( - if Time::from_millis(10)>, -} - -pub struct RunContextSetup{ manual_mouse_lock:bool, mouse:crate::physics::MouseState,//std::sync::Arc> + screen_size:glam::UVec2, user_settings:crate::settings::UserSettings, window:winit::window::Window, - physics:crate::physics::PhysicsState, - graphics:crate::graphics::GraphicsState, + //physics_thread:crate::worker::QNWorker>, } -impl RunContextSetup { - pub fn new(context:&crate::setup::SetupContext,window:winit::window::Window)->Self{ - //wee - let user_settings=crate::settings::read_user_settings(); - - let args:Vec=std::env::args().collect(); - let indexed_model_instances=if args.len()==2{ - crate::load_file(std::path::PathBuf::from(&args[1])) - }else{ - None - }.unwrap_or(crate::default_models()); - - let mut graphics=crate::graphics::GraphicsState::new(&context.device,&context.queue); - graphics.load_user_settings(&user_settings); - graphics.generate_models(&context.device,&context.queue,indexed_model_instances); - - let mut physics=crate::physics::PhysicsState::default(); - physics.load_user_settings(&user_settings); - physics.generate_models(&indexed_model_instances); - - Self{ - manual_mouse_lock:false, - mouse:crate::physics::MouseState::default(), - user_settings, - window, - graphics, - physics, - } - } - fn window_event(&self,time:crate::integer::Time,event: winit::event::WindowEvent) { +impl RunContext{ + fn window_event(&mut self,time:crate::integer::Time,event: winit::event::WindowEvent) { match event { winit::event::WindowEvent::DroppedFile(path)=>{ - let sender=self.sender.clone();//mpsc - std::thread::spawn(move ||{ - let indexed_model_instances=crate::load_file(path); - sender.send(Instruction::Die(indexed_model_instances)); - }); + // let sender=self.sender.clone();//mpsc + // std::thread::spawn(move ||{ + // let indexed_model_instances=crate::load_file(path); + // sender.send(Instruction::Die(indexed_model_instances)); + // }); + let indexed_model_instances=crate::load_file(path); + //self.physics= + println!("unimplemented"); }, winit::event::WindowEvent::Focused(state)=>{ //pause unpause @@ -187,44 +158,75 @@ impl RunContextSetup { _=>(), } } +} - pub fn into_worker(self)->crate::worker::QNWorker>{ +pub struct RunContextSetup{ + user_settings:crate::settings::UserSettings, + window:winit::window::Window, + physics:crate::physics::PhysicsState, + graphics:crate::graphics::GraphicsState, +} + +impl RunContextSetup{ + pub fn new(context:&crate::setup::SetupContext,window:winit::window::Window)->Self{ + //wee + let user_settings=crate::settings::read_user_settings(); + + let args:Vec=std::env::args().collect(); + let indexed_model_instances=if args.len()==2{ + crate::load_file(std::path::PathBuf::from(&args[1])) + }else{ + None + }.unwrap_or(crate::default_models()); + + let mut graphics=crate::graphics::GraphicsState::new(&context.device,&context.queue); + graphics.load_user_settings(&user_settings); + graphics.generate_models(&context.device,&context.queue,indexed_model_instances); + + let mut physics=crate::physics::PhysicsState::default(); + physics.load_user_settings(&user_settings); + physics.generate_models(&indexed_model_instances); + + Self{ + user_settings, + window, + graphics, + physics, + } + } + + fn into_context(self)->RunContext{ + RunContext{ + manual_mouse_lock:false, + mouse:crate::physics::MouseState::default(), + user_settings:self.user_settings, + window:self.window, + physics:self.physics, + graphics:self.graphics, + } + } + + pub fn into_worker(self,setup_context:crate::setup::SetupContext)->crate::worker::QNWorker>{ let run_context=self.into_context(); crate::worker::QNWorker::new(move |ins:TimedInstruction|{ match ins.instruction{ RunInstruction::RequestRedraw=>{ - self.window.request_redraw(); + run_context.window.request_redraw(); } RunInstruction::WindowEvent(window_event)=>{ - self.window_event(ins.time,window_event); + run_context.window_event(ins.time,window_event); }, RunInstruction::DeviceEvent(device_event)=>{ - self.device_event(ins.time,device_event); + run_context.device_event(ins.time,device_event); }, RunInstruction::Resize(size)=>{ setup_context.config.width=size.width.max(1); setup_context.config.height=size.height.max(1); setup_context.surface.configure(&setup_context.device,&setup_context.config); - physics_thread.send(TimedInstruction{time:ins.time,instruction:PhysicsInstruction::Resize(size)}); + run_context.physics_thread.send(TimedInstruction{time:ins.time,instruction:PhysicsInstruction::Resize(size)}); } RunInstruction::Render=>{ - let frame=match setup_context.surface.get_current_texture(){ - Ok(frame)=>frame, - Err(_)=>{ - setup_context.surface.configure(&setup_context.device,&setup_context.config); - setup_context.surface - .get_current_texture() - .expect("Failed to acquire next surface texture!") - } - }; - let view=frame.texture.create_view(&wgpu::TextureViewDescriptor{ - format:Some(setup_context.config.view_formats[0]), - ..wgpu::TextureViewDescriptor::default() - }); - - physics_thread.send(TimedInstruction{time:ins.time,instruction:PhysicsInstruction::Render(view)}); - - frame.present(); + // } } })