Compare commits

..

6 Commits

Author SHA1 Message Date
580bbf2cc5 schedule frames at a fixed interval 2023-11-08 18:20:50 -08:00
08f6d928cf bizzare slow motion gameplay 2023-11-08 18:20:49 -08:00
de7b7ba7be defer resize to next frame render 2023-11-08 18:20:19 -08:00
008c66e052 TrussPart 2023-11-07 20:54:49 -08:00
ba250277bd textures for spheres and cylinders 2023-11-07 20:45:05 -08:00
085d4e7912 use cubes instead of teapots and monkeys 2023-11-07 16:54:44 -08:00
6 changed files with 62 additions and 188 deletions

View File

@@ -16,13 +16,15 @@ WorkerDescription{
//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<'a>(
scope:&'a std::thread::Scope<'a,'_>,
mut graphics:crate::graphics::GraphicsState,
mut config:wgpu::SurfaceConfiguration,
surface:wgpu::Surface,
device:wgpu::Device,
queue:wgpu::Queue,
)->crate::compat_worker::INWorker<'a,Instruction>{
crate::compat_worker::INWorker::new(move |ins:Instruction|{
)->crate::worker::INWorker<'a,Instruction>{
let mut resize=None;
crate::worker::INWorker::new(scope,move |ins:Instruction|{
match ins{
Instruction::GenerateModels(indexed_model_instances)=>{
graphics.generate_models(&device,&queue,indexed_model_instances);
@@ -31,13 +33,20 @@ pub fn new<'a>(
graphics.clear();
},
Instruction::Resize(size,user_settings)=>{
println!("Resizing to {:?}",size);
config.width=size.width.max(1);
config.height=size.height.max(1);
surface.configure(&device,&config);
graphics.resize(&device,&config,&user_settings);
resize=Some((size,user_settings));
}
Instruction::Render(physics_output,predicted_time,mouse_pos)=>{
if let Some((size,user_settings))=&resize{
println!("Resizing to {:?}",size);
let t0=std::time::Instant::now();
config.width=size.width.max(1);
config.height=size.height.max(1);
surface.configure(&device,&config);
graphics.resize(&device,&config,user_settings);
println!("Resize took {:?}",t0.elapsed());
}
//clear every time w/e
resize=None;
//this has to go deeper somehow
let frame=match surface.get_current_texture(){
Ok(frame)=>frame,
@@ -59,4 +68,4 @@ pub fn new<'a>(
}
}
})
}
}

View File

@@ -217,9 +217,9 @@ type RobloxWedgeDescription=[Option<RobloxFaceTextureDescription>;5];
type RobloxCornerWedgeDescription=[Option<RobloxFaceTextureDescription>;5];
#[derive(Clone,Eq,Hash,PartialEq)]
enum RobloxBasePartDescription{
Sphere,
Sphere(RobloxPartDescription),
Part(RobloxPartDescription),
Cylinder,
Cylinder(RobloxPartDescription),
Wedge(RobloxWedgeDescription),
CornerWedge(RobloxCornerWedgeDescription),
}
@@ -298,6 +298,7 @@ pub fn generate_indexed_models(dom:rbx_dom_weak::WeakDom) -> crate::model::Index
panic!("Part has no Shape!");
}
},
"TrussPart"=>primitives::Primitives::Cube,
"WedgePart"=>primitives::Primitives::Wedge,
"CornerWedgePart"=>primitives::Primitives::CornerWedge,
_=>{
@@ -392,9 +393,9 @@ pub fn generate_indexed_models(dom:rbx_dom_weak::WeakDom) -> crate::model::Index
f5,//Cube::Front
]=part_texture_description;
let basepart_texture_description=match shape{
primitives::Primitives::Sphere=>RobloxBasePartDescription::Sphere,
primitives::Primitives::Sphere=>RobloxBasePartDescription::Sphere([f0,f1,f2,f3,f4,f5]),
primitives::Primitives::Cube=>RobloxBasePartDescription::Part([f0,f1,f2,f3,f4,f5]),
primitives::Primitives::Cylinder=>RobloxBasePartDescription::Cylinder,
primitives::Primitives::Cylinder=>RobloxBasePartDescription::Cylinder([f0,f1,f2,f3,f4,f5]),
//use front face texture first and use top face texture as a fallback
primitives::Primitives::Wedge=>RobloxBasePartDescription::Wedge([
f0,//Cube::Right->Wedge::Right
@@ -420,8 +421,9 @@ pub fn generate_indexed_models(dom:rbx_dom_weak::WeakDom) -> crate::model::Index
let model_id=indexed_models.len();
model_id_from_description.insert(basepart_texture_description.clone(),model_id);//borrow checker going crazy
indexed_models.push(match basepart_texture_description{
RobloxBasePartDescription::Sphere=>primitives::unit_sphere(),
RobloxBasePartDescription::Part(part_texture_description)=>{
RobloxBasePartDescription::Sphere(part_texture_description)
|RobloxBasePartDescription::Cylinder(part_texture_description)
|RobloxBasePartDescription::Part(part_texture_description)=>{
let mut cube_face_description=primitives::CubeFaceDescription::default();
for (face_id,roblox_face_description) in part_texture_description.iter().enumerate(){
cube_face_description.insert(
@@ -441,7 +443,6 @@ pub fn generate_indexed_models(dom:rbx_dom_weak::WeakDom) -> crate::model::Index
}
primitives::generate_partial_unit_cube(cube_face_description)
},
RobloxBasePartDescription::Cylinder=>primitives::unit_cylinder(),
RobloxBasePartDescription::Wedge(wedge_texture_description)=>{
let mut wedge_face_description=primitives::WedgeFaceDescription::default();
for (face_id,roblox_face_description) in wedge_texture_description.iter().enumerate(){

View File

@@ -23,11 +23,11 @@ pub enum Instruction{
//Graphics(crate::graphics_worker::Instruction),
}
pub fn new(mut physics:crate::physics::PhysicsState,mut graphics_worker:crate::compat_worker::INWorker<crate::graphics_worker::Instruction>)->crate::compat_worker::QNWorker<TimedInstruction<Instruction>>{
pub fn new<'a>(scope:&'a std::thread::Scope<'a,'_>,mut physics:crate::physics::PhysicsState,graphics_worker:crate::worker::INWorker<'a,crate::graphics_worker::Instruction>)->crate::worker::QNWorker<'a,TimedInstruction<Instruction>>{
let mut mouse_blocking=true;
let mut last_mouse_time=physics.next_mouse.time;
let mut timeline=std::collections::VecDeque::new();
crate::compat_worker::QNWorker::new(move |ins:TimedInstruction<Instruction>|{
crate::worker::QNWorker::new(scope,move |ins:TimedInstruction<Instruction>|{
if if let Some(phys_input)=match &ins.instruction{
Instruction::Input(input_instruction)=>match input_instruction{
&InputInstruction::MoveMouse(m)=>{
@@ -113,10 +113,11 @@ pub enum Instruction{
}
match ins.instruction{
Instruction::Render=>{
graphics_worker.send(crate::graphics_worker::Instruction::Render(physics.output(),ins.time,physics.next_mouse.pos)).unwrap();
let _=graphics_worker.send(crate::graphics_worker::Instruction::Render(physics.output(),ins.time,physics.next_mouse.pos));
},
Instruction::Resize(size,user_settings)=>{
graphics_worker.send(crate::graphics_worker::Instruction::Resize(size,user_settings)).unwrap();
//block!
graphics_worker.blocking_send(crate::graphics_worker::Instruction::Resize(size,user_settings)).unwrap();
},
Instruction::GenerateModels(indexed_model_instances)=>{
physics.generate_models(&indexed_model_instances);

View File

@@ -126,152 +126,8 @@ const CORNERWEDGE_DEFAULT_NORMALS:[Planar64Vec3;5]=[
Planar64Vec3::int( 0,-1, 0),//CornerWedge::Bottom
Planar64Vec3::int( 0, 0,-1),//CornerWedge::Front
];
const GON:u32=6;
const SPHERE_STUFF:([[[[u32;3];4];((GON-1)*(GON-1)) as usize];6])={
const CUBE_EDGES:[[u32;2];12]=[[0,1],[0,3],[0,7],[1,2],[1,6],[2,3],[2,5],[3,4],[4,5],[4,7],[5,6],[6,7]];
const fn get_pos_id(p:[[u32;3];4],tex_id:u32)->u32{
if p[0][1]==tex_id{
return p[0][0];
}
if p[1][1]==tex_id{
return p[1][0];
}
if p[2][1]==tex_id{
return p[2][0];
}
if p[3][1]==tex_id{
return p[3][0];
}
panic!("tex missing")
}
const fn get_edge_id(v0:u32,v1:u32)->(u32,bool){
(match if v0<v1{[v0,v1]}else{[v1,v0]}{
[0,1]=>0,
[0,3]=>1,
[0,7]=>2,
[1,2]=>3,
[1,6]=>4,
[2,3]=>5,
[2,5]=>6,
[3,4]=>7,
[4,5]=>8,
[4,7]=>9,
[5,6]=>10,
[6,7]=>11,
_=>panic!(":)")
},v0<v1)
}
const fn get_idx(face_id:u32,v00:u32,v10:u32,v11:u32,v01:u32,x:u32,y:u32)->u32{
if x==0&&y==0{
return v00
}
if x==0&&y==GON-1{
return v01
}
if x==GON-1&&y==GON-1{
return v11
}
if x==GON-1&&y==0{
return v10
}
if x==0{
//left edge
let (edge_id,parity)=get_edge_id(v00,v01);
if parity{
return 8+edge_id*(GON-2)+(y-1)
}else{
return 8+edge_id*(GON-2)+(GON-(y-1))
}
}
if x==GON-1{
//right edge
let (edge_id,parity)=get_edge_id(v10,v11);
if parity{
return 8+edge_id*(GON-2)+(y-1)
}else{
return 8+edge_id*(GON-2)+(GON-(y-1))
}
}
if y==0{
//top edge
let (edge_id,parity)=get_edge_id(v00,v10);
if parity{
return 8+edge_id*(GON-2)+(x-1)
}else{
return 8+edge_id*(GON-2)+(GON-(x-1))
}
}
if y==GON-1{
//bottom edge
let (edge_id,parity)=get_edge_id(v01,v11);
if parity{
return 8+edge_id*(GON-2)+(x-1)
}else{
return 8+edge_id*(GON-2)+(GON-(x-1))
}
}
return 8+12*(GON-2)+face_id*(GON-2)*(GON-2)+(x-1)+(y-1)*(GON-2)
}
//topology (indexed polys)
let mut polys=[[[[0u32;3];4];((GON-1)*(GON-1)) as usize];6];
let mut face_id=0;
while face_id<6{
let p=CUBE_DEFAULT_POLYS[face_id];
//vertex ids
let v00=get_pos_id(p,0);//top left
let v10=get_pos_id(p,1);//top right
let v11=get_pos_id(p,2);//bottom right
let v01=get_pos_id(p,3);//bottom left
let mut i=0;
while i<(GON-1)*(GON-1){
let x=i as u32%GON;
let y=i as u32/GON;
let i00=get_idx(face_id as u32,v00,v10,v11,v01,x+0,y+0);
let i10=get_idx(face_id as u32,v00,v10,v11,v01,x+1,y+0);
let i11=get_idx(face_id as u32,v00,v10,v11,v01,x+1,y+1);
let i01=get_idx(face_id as u32,v00,v10,v11,v01,x+0,y+1);
//[pos,tex,norm]
polys[face_id][i as usize][0]=[i00,(x+0)+(y+0)*GON,i00];
polys[face_id][i as usize][1]=[i10,(x+1)+(y+0)*GON,i10];
polys[face_id][i as usize][2]=[i11,(x+1)+(y+1)*GON,i11];
polys[face_id][i as usize][3]=[i01,(x+0)+(y+1)*GON,i01];
i+=1;
}
face_id+=1;
}
//verts
const N_VERTS:usize=(8+12*(GON-2)+6*(GON-2)*(GON-2)) as usize;
let mut verts=[Planar64Vec3::ZERO;N_VERTS];
let mut i=0;
while i<8{
verts[i]=CUBE_DEFAULT_VERTICES[i].normalize();
i+=1;
}
i=0;
while i<12{
//
}
i=0;
while i<6{
//
}
//tex
let mut tex=[TextureCoordinate::new(0.0,0.0);(GON*GON) as usize];
let mut i=0;
while i<(GON*GON) as usize{
let x=i as u32%GON;
let y=i as u32/GON;
tex[i]=TextureCoordinate::new(x as f32/(GON-1) as f32,y as f32/(GON-1) as f32);
i+=1;
}
(verts,tex,polys)
};
pub fn unit_sphere()->crate::model::IndexedModel{
let mut indexed_model=crate::model::generate_indexed_model_list_from_obj(obj::ObjData::load_buf(&include_bytes!("../models/suzanne.obj")[..]).unwrap(),Color4::ONE).remove(0);
for pos in indexed_model.unique_pos.iter_mut(){
*pos=*pos/2;
}
indexed_model
unit_cube()
}
#[derive(Default)]
pub struct CubeFaceDescription([Option<FaceDescription>;6]);
@@ -293,13 +149,8 @@ pub fn unit_cube()->crate::model::IndexedModel{
t.insert(CubeFace::Front,FaceDescription::default());
generate_partial_unit_cube(t)
}
const TEAPOT_TRANSFORM:crate::integer::Planar64Mat3=crate::integer::Planar64Mat3::int_from_cols_array([0,1,0, -1,0,0, 0,0,1]);
pub fn unit_cylinder()->crate::model::IndexedModel{
let mut indexed_model=crate::model::generate_indexed_model_list_from_obj(obj::ObjData::load_buf(&include_bytes!("../models/teapot.obj")[..]).unwrap(),Color4::ONE).remove(0);
for pos in indexed_model.unique_pos.iter_mut(){
*pos=TEAPOT_TRANSFORM*(*pos)/10;
}
indexed_model
unit_cube()
}
#[derive(Default)]
pub struct WedgeFaceDescription([Option<FaceDescription>;5]);

View File

@@ -232,20 +232,32 @@ impl SetupContextSetup{
let (window,event_loop,setup_context)=self.into_split();
//dedicated thread to ping request redraw back and resize the window doesn't seem logical
let window=crate::window::WindowContextSetup::new(&setup_context,window);
//the thread that spawns the physics thread
let window_thread=window.into_worker(setup_context);
println!("Entering event loop...");
//but here I am doing it
let root_time=std::time::Instant::now();
run_event_loop(event_loop,window_thread,root_time).unwrap();
std::thread::scope(|s|{
let window=crate::window::WindowContextSetup::new(&setup_context,window);
//the thread that spawns the physics thread
let window_thread=window.into_worker(s,setup_context);
//schedule frames at 165fps
let event_loop_proxy=event_loop.create_proxy();
s.spawn(move ||{
loop{
std::thread::sleep(std::time::Duration::from_nanos(1_000_000_000/165));
event_loop_proxy.send_event(()).ok();
}
});
println!("Entering event loop...");
run_event_loop(event_loop,window_thread,root_time).unwrap();
});
}
}
fn run_event_loop(
event_loop:winit::event_loop::EventLoop<()>,
mut window_thread:crate::compat_worker::QNWorker<TimedInstruction<WindowInstruction>>,
window_thread:crate::worker::QNWorker<TimedInstruction<WindowInstruction>>,
root_time:std::time::Instant
)->Result<(),winit::error::EventLoopError>{
event_loop.run(move |event,elwt|{
@@ -256,7 +268,7 @@ fn run_event_loop(
// winit::event_loop::ControlFlow::Poll
// };
match event{
winit::event::Event::AboutToWait=>{
winit::event::Event::UserEvent(())=>{
window_thread.send(TimedInstruction{time,instruction:WindowInstruction::RequestRedraw}).unwrap();
}
winit::event::Event::WindowEvent {
@@ -300,4 +312,4 @@ fn run_event_loop(
_=>{}
}
})
}
}

View File

@@ -16,7 +16,7 @@ struct WindowContext<'a>{
screen_size:glam::UVec2,
user_settings:crate::settings::UserSettings,
window:winit::window::Window,
physics_thread:crate::compat_worker::QNWorker<'a, TimedInstruction<crate::physics_worker::Instruction>>,
physics_thread:crate::worker::QNWorker<'a,TimedInstruction<crate::physics_worker::Instruction>>,
}
impl WindowContext<'_>{
@@ -194,9 +194,9 @@ impl WindowContextSetup{
}
}
fn into_context<'a>(self,setup_context:crate::setup::SetupContext)->WindowContext<'a>{
fn into_context<'a>(self,scope:&'a std::thread::Scope<'a,'_>,setup_context:crate::setup::SetupContext)->WindowContext<'a>{
let screen_size=glam::uvec2(setup_context.config.width,setup_context.config.height);
let graphics_thread=crate::graphics_worker::new(self.graphics,setup_context.config,setup_context.surface,setup_context.device,setup_context.queue);
let graphics_thread=crate::graphics_worker::new(scope,self.graphics,setup_context.config,setup_context.surface,setup_context.device,setup_context.queue);
WindowContext{
manual_mouse_lock:false,
mouse:crate::physics::MouseState::default(),
@@ -204,13 +204,13 @@ impl WindowContextSetup{
screen_size,
user_settings:self.user_settings,
window:self.window,
physics_thread:crate::physics_worker::new(self.physics,graphics_thread),
physics_thread:crate::physics_worker::new(scope,self.physics,graphics_thread),
}
}
pub fn into_worker<'a>(self,setup_context:crate::setup::SetupContext)->crate::compat_worker::QNWorker<'a,TimedInstruction<WindowInstruction>>{
let mut window_context=self.into_context(setup_context);
crate::compat_worker::QNWorker::new(move |ins:TimedInstruction<WindowInstruction>|{
pub fn into_worker<'a>(self,scope:&'a std::thread::Scope<'a,'_>,setup_context:crate::setup::SetupContext)->crate::worker::QNWorker<'a,TimedInstruction<WindowInstruction>>{
let mut window_context=self.into_context(scope,setup_context);
crate::worker::QNWorker::new(scope,move |ins:TimedInstruction<WindowInstruction>|{
match ins.instruction{
WindowInstruction::RequestRedraw=>{
window_context.window.request_redraw();
@@ -240,4 +240,4 @@ impl WindowContextSetup{
}
})
}
}
}