2023-10-19 21:56:39 +00:00
use std ::time ::Instant ;
2023-10-20 02:19:05 +00:00
use physics ::PhysicsInstruction ;
use render_thread ::InputInstruction ;
2023-09-20 00:53:29 +00:00
use instruction ::{ TimedInstruction , InstructionConsumer } ;
2023-08-30 01:20:58 +00:00
2023-10-06 03:32:25 +00:00
mod bvh ;
2023-10-06 03:32:02 +00:00
mod aabb ;
2023-09-22 22:21:13 +00:00
mod model ;
2023-09-27 09:12:20 +00:00
mod model_graphics ;
2023-09-22 22:19:44 +00:00
mod zeroes ;
2023-10-04 22:58:02 +00:00
mod worker ;
2023-10-19 00:17:21 +00:00
mod integer ;
2023-10-04 22:58:02 +00:00
mod physics ;
2023-10-19 00:17:21 +00:00
mod graphics ;
2023-10-10 00:09:24 +00:00
mod settings ;
2023-09-22 22:19:44 +00:00
mod framework ;
2023-09-23 02:41:27 +00:00
mod primitives ;
2023-09-22 22:19:44 +00:00
mod instruction ;
mod load_roblox ;
2023-10-20 01:42:00 +00:00
mod render_thread ;
2023-10-05 03:04:04 +00:00
2023-10-04 02:43:41 +00:00
pub struct GlobalState {
start_time : std ::time ::Instant ,
manual_mouse_lock :bool ,
2023-10-19 21:56:39 +00:00
mouse :std ::sync ::Arc < std ::sync ::Mutex < physics ::MouseState > > ,
2023-10-10 02:44:49 +00:00
user_settings :settings ::UserSettings ,
2023-10-19 21:56:39 +00:00
//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 :worker ::INWorker < graphics ::GraphicsInstruction > ,
physics_thread :worker ::QNWorker < TimedInstruction < InputInstruction > > ,
2023-10-04 02:43:41 +00:00
}
2023-10-20 02:19:05 +00:00
fn load_file ( path : std ::path ::PathBuf ) ->Option < model ::IndexedModelInstances > {
println! ( " Loading file: {:?} " , & path ) ;
//oh boy! let's load the map!
if let Ok ( file ) = std ::fs ::File ::open ( path ) {
let mut input = std ::io ::BufReader ::new ( file ) ;
let mut first_8 = [ 0 u8 ; 8 ] ;
//.rbxm roblox binary = "<roblox!"
//.rbxmx roblox xml = "<roblox "
//.bsp = "VBSP"
//.vmf =
//.snf = "SNMF"
//.snf = "SNBF"
if let ( Ok ( ( ) ) , Ok ( ( ) ) ) = ( std ::io ::Read ::read_exact ( & mut input , & mut first_8 ) , std ::io ::Seek ::rewind ( & mut input ) ) {
match & first_8 [ 0 .. 4 ] {
b " <rob " = > {
match match & first_8 [ 4 .. 8 ] {
b " lox! " = > rbx_binary ::from_reader ( input ) . map_err ( | e | format! ( " {:?} " , e ) ) ,
b " lox " = > rbx_xml ::from_reader ( input , rbx_xml ::DecodeOptions ::default ( ) ) . map_err ( | e | format! ( " {:?} " , e ) ) ,
other = > Err ( format! ( " Unknown Roblox file type {:?} " , other ) ) ,
} {
Ok ( dom ) = > Some ( load_roblox ::generate_indexed_models ( dom ) ) ,
Err ( e ) = > {
println! ( " Error loading roblox file: {:?} " , e ) ;
None
} ,
}
} ,
//b"VBSP"=>Some(load_bsp::generate_indexed_models(input)),
//b"SNFM"=>Some(sniffer::generate_indexed_models(input)),
//b"SNFB"=>Some(sniffer::load_bot(input)),
other = > {
println! ( " loser file {:?} " , other ) ;
None
} ,
}
} else {
println! ( " Failed to read first 8 bytes and seek back to beginning of file. " ) ;
None
}
} else {
println! ( " Could not open file " ) ;
None
}
}
2023-10-04 02:43:41 +00:00
impl framework ::Example for GlobalState {
2023-09-06 21:39:44 +00:00
fn optional_features ( ) -> wgpu ::Features {
wgpu ::Features ::TEXTURE_COMPRESSION_ASTC
| wgpu ::Features ::TEXTURE_COMPRESSION_ETC2
2023-09-28 17:58:51 +00:00
}
fn required_features ( ) -> wgpu ::Features {
wgpu ::Features ::TEXTURE_COMPRESSION_BC
2023-09-06 21:39:44 +00:00
}
2023-09-21 18:55:31 +00:00
fn required_limits ( ) -> wgpu ::Limits {
wgpu ::Limits ::default ( ) //framework.rs was using goofy limits that caused me a multi-day headache
}
2023-09-06 21:39:44 +00:00
fn init (
config : & wgpu ::SurfaceConfiguration ,
_adapter : & wgpu ::Adapter ,
device : & wgpu ::Device ,
queue : & wgpu ::Queue ,
) -> Self {
2023-10-10 02:44:49 +00:00
//wee
let user_settings = settings ::read_user_settings ( ) ;
2023-09-29 02:10:22 +00:00
let mut indexed_models = Vec ::new ( ) ;
2023-09-27 09:12:20 +00:00
indexed_models . append ( & mut model ::generate_indexed_model_list_from_obj ( obj ::ObjData ::load_buf ( & include_bytes! ( " ../models/teslacyberv3.0.obj " ) [ .. ] ) . unwrap ( ) , glam ::Vec4 ::ONE ) ) ;
2023-09-30 23:18:23 +00:00
indexed_models . push ( primitives ::unit_sphere ( ) ) ;
indexed_models . push ( primitives ::unit_cylinder ( ) ) ;
indexed_models . push ( primitives ::unit_cube ( ) ) ;
2023-09-29 02:10:22 +00:00
println! ( " models.len = {:?} " , indexed_models . len ( ) ) ;
2023-09-27 09:12:20 +00:00
indexed_models [ 0 ] . instances . push ( model ::ModelInstance {
transform :integer ::Planar64Affine3 ::try_from ( glam ::Affine3A ::from_translation ( glam ::vec3 ( 10. , 0. , - 10. ) ) ) . unwrap ( ) ,
2023-10-04 02:45:01 +00:00
.. Default ::default ( )
2023-09-21 20:02:01 +00:00
} ) ;
2023-09-21 05:37:03 +00:00
//quad monkeys
2023-09-27 09:12:20 +00:00
indexed_models [ 1 ] . instances . push ( model ::ModelInstance {
transform :integer ::Planar64Affine3 ::try_from ( glam ::Affine3A ::from_translation ( glam ::vec3 ( 10. , 5. , 10. ) ) ) . unwrap ( ) ,
2023-10-04 02:45:01 +00:00
.. Default ::default ( )
2023-09-21 20:02:01 +00:00
} ) ;
2023-09-27 09:12:20 +00:00
indexed_models [ 1 ] . instances . push ( model ::ModelInstance {
transform :integer ::Planar64Affine3 ::try_from ( glam ::Affine3A ::from_translation ( glam ::vec3 ( 20. , 5. , 10. ) ) ) . unwrap ( ) ,
2023-09-21 20:02:01 +00:00
color :glam ::vec4 ( 1.0 , 0.0 , 0.0 , 1.0 ) ,
2023-10-04 02:45:01 +00:00
.. Default ::default ( )
2023-09-21 20:02:01 +00:00
} ) ;
2023-09-27 09:12:20 +00:00
indexed_models [ 1 ] . instances . push ( model ::ModelInstance {
transform :integer ::Planar64Affine3 ::try_from ( glam ::Affine3A ::from_translation ( glam ::vec3 ( 10. , 5. , 20. ) ) ) . unwrap ( ) ,
2023-09-21 20:02:01 +00:00
color :glam ::vec4 ( 0.0 , 1.0 , 0.0 , 1.0 ) ,
2023-10-04 02:45:01 +00:00
.. Default ::default ( )
2023-09-21 20:02:01 +00:00
} ) ;
2023-09-27 09:12:20 +00:00
indexed_models [ 1 ] . instances . push ( model ::ModelInstance {
transform :integer ::Planar64Affine3 ::try_from ( glam ::Affine3A ::from_translation ( glam ::vec3 ( 20. , 5. , 20. ) ) ) . unwrap ( ) ,
2023-09-21 20:02:01 +00:00
color :glam ::vec4 ( 0.0 , 0.0 , 1.0 , 1.0 ) ,
2023-10-04 02:45:01 +00:00
.. Default ::default ( )
2023-10-03 23:34:54 +00:00
} ) ;
//decorative monkey
2023-09-27 09:12:20 +00:00
indexed_models [ 1 ] . instances . push ( model ::ModelInstance {
transform :integer ::Planar64Affine3 ::try_from ( glam ::Affine3A ::from_translation ( glam ::vec3 ( 15. , 10. , 15. ) ) ) . unwrap ( ) ,
2023-10-03 23:34:54 +00:00
color :glam ::vec4 ( 0.5 , 0.5 , 0.5 , 0.5 ) ,
attributes :model ::CollisionAttributes ::Decoration ,
2023-10-04 02:45:01 +00:00
.. Default ::default ( )
2023-09-21 20:02:01 +00:00
} ) ;
2023-09-21 05:37:03 +00:00
//teapot
2023-09-27 09:12:20 +00:00
indexed_models [ 2 ] . instances . push ( model ::ModelInstance {
transform :integer ::Planar64Affine3 ::try_from ( glam ::Affine3A ::from_scale_rotation_translation ( glam ::vec3 ( 0.5 , 1.0 , 0.2 ) , glam ::quat ( - 0.22248298016985793 , - 0.839457167990537 , - 0.05603504040830783 , - 0.49261857546227916 ) , glam ::vec3 ( - 10. , 7. , 10. ) ) ) . unwrap ( ) ,
2023-10-04 02:45:01 +00:00
.. Default ::default ( )
2023-09-21 20:02:01 +00:00
} ) ;
2023-09-21 05:37:03 +00:00
//ground
2023-09-27 09:12:20 +00:00
indexed_models [ 3 ] . instances . push ( model ::ModelInstance {
transform :integer ::Planar64Affine3 ::try_from ( glam ::Affine3A ::from_translation ( glam ::vec3 ( 0. , 0. , 0. ) ) * glam ::Affine3A ::from_scale ( glam ::vec3 ( 160.0 , 1.0 , 160.0 ) ) ) . unwrap ( ) ,
2023-10-04 02:45:01 +00:00
.. Default ::default ( )
2023-09-21 20:02:01 +00:00
} ) ;
2023-09-06 21:39:44 +00:00
2023-10-19 00:17:21 +00:00
let mut graphics = GraphicsState ::new ( ) ;
2023-09-21 05:36:42 +00:00
2023-10-10 02:44:49 +00:00
graphics . load_user_settings ( & user_settings ) ;
2023-09-29 02:10:22 +00:00
let indexed_model_instances = model ::IndexedModelInstances {
textures :Vec ::new ( ) ,
models :indexed_models ,
2023-09-27 09:12:20 +00:00
spawn_point :integer ::Planar64Vec3 ::Y * 50 ,
2023-10-04 02:42:07 +00:00
modes :Vec ::new ( ) ,
2023-09-29 02:10:22 +00:00
} ;
2023-10-05 03:04:04 +00:00
//how to multithread
//1. build
physics . generate_models ( & indexed_model_instances ) ;
//2. move
let physics_thread = physics . into_worker ( ) ;
//3. forget
let mut state = GlobalState {
start_time :Instant ::now ( ) ,
manual_mouse_lock :false ,
mouse :physics ::MouseState ::default ( ) ,
2023-10-10 02:44:49 +00:00
user_settings ,
2023-10-05 03:04:04 +00:00
graphics ,
physics_thread ,
} ;
2023-10-04 02:43:41 +00:00
state . generate_model_graphics ( & device , & queue , indexed_model_instances ) ;
2023-09-21 05:36:42 +00:00
2023-10-02 00:18:50 +00:00
let args :Vec < String > = std ::env ::args ( ) . collect ( ) ;
if args . len ( ) = = 2 {
2023-10-20 02:19:05 +00:00
let indexed_model_instances = load_file ( std ::path ::PathBuf ::from ( & args [ 1 ] ) ) ;
state . render_thread = RenderThread ::new ( user_settings , indexed_model_instances ) ;
2023-10-02 00:18:50 +00:00
}
2023-10-04 02:43:41 +00:00
return state ;
2023-09-06 21:39:44 +00:00
}
2023-10-02 00:18:29 +00:00
#[ allow(clippy::single_match) ]
fn update ( & mut self , window : & winit ::window ::Window , device : & wgpu ::Device , queue : & wgpu ::Queue , event : winit ::event ::WindowEvent ) {
2023-09-27 09:12:20 +00:00
let time = integer ::Time ::from_nanos ( self . start_time . elapsed ( ) . as_nanos ( ) as i64 ) ;
2023-10-02 00:18:29 +00:00
match event {
2023-10-20 02:29:32 +00:00
winit ::event ::WindowEvent ::DroppedFile ( path ) = > {
std ::thread ::spawn ( move | | {
let indexed_model_instances = load_file ( path ) ;
self . render_thread . send ( Instruction ::Die ( indexed_model_instances ) ) ;
} ) ;
} ,
2023-10-02 02:29:29 +00:00
winit ::event ::WindowEvent ::Focused ( state ) = > {
//pause unpause
//recalculate pressed keys on focus
2023-10-01 22:54:50 +00:00
} ,
winit ::event ::WindowEvent ::KeyboardInput {
input :winit ::event ::KeyboardInput { state , virtual_keycode , .. } ,
2023-09-06 21:39:44 +00:00
..
2023-10-01 22:54:50 +00:00
} = > {
2023-09-20 00:53:29 +00:00
let s = match state {
winit ::event ::ElementState ::Pressed = > true ,
winit ::event ::ElementState ::Released = > false ,
} ;
2023-10-01 22:54:50 +00:00
match virtual_keycode {
Some ( winit ::event ::VirtualKeyCode ::Tab ) = > {
2023-10-02 09:40:36 +00:00
if s {
self . manual_mouse_lock = false ;
2023-10-05 03:04:04 +00:00
match window . set_cursor_position ( winit ::dpi ::PhysicalPosition ::new ( self . graphics . camera . screen_size . x as f32 / 2.0 , self . graphics . camera . screen_size . y as f32 / 2.0 ) ) {
2023-10-02 09:40:36 +00:00
Ok ( ( ) ) = > ( ) ,
Err ( e ) = > println! ( " Could not set cursor position: {:?} " , e ) ,
}
match window . set_cursor_grab ( winit ::window ::CursorGrabMode ::None ) {
Ok ( ( ) ) = > ( ) ,
Err ( e ) = > println! ( " Could not release cursor: {:?} " , e ) ,
}
} else {
//if cursor is outside window don't lock but apparently there's no get pos function
//let pos=window.get_cursor_pos();
match window . set_cursor_grab ( winit ::window ::CursorGrabMode ::Locked ) {
Ok ( ( ) ) = > ( ) ,
Err ( _ ) = > {
match window . set_cursor_grab ( winit ::window ::CursorGrabMode ::Confined ) {
Ok ( ( ) ) = > ( ) ,
Err ( e ) = > {
self . manual_mouse_lock = true ;
println! ( " Could not confine cursor: {:?} " , e )
} ,
}
}
}
}
window . set_cursor_visible ( s ) ;
} ,
2023-10-01 22:54:50 +00:00
Some ( winit ::event ::VirtualKeyCode ::F11 ) = > {
if s {
if window . fullscreen ( ) . is_some ( ) {
window . set_fullscreen ( None ) ;
} else {
window . set_fullscreen ( Some ( winit ::window ::Fullscreen ::Borderless ( None ) ) ) ;
}
}
} ,
Some ( winit ::event ::VirtualKeyCode ::Escape ) = > {
if s {
self . manual_mouse_lock = false ;
match window . set_cursor_grab ( winit ::window ::CursorGrabMode ::None ) {
Ok ( ( ) ) = > ( ) ,
Err ( e ) = > println! ( " Could not release cursor: {:?} " , e ) ,
}
window . set_cursor_visible ( true ) ;
}
} ,
Some ( keycode ) = > {
if let Some ( input_instruction ) = match keycode {
winit ::event ::VirtualKeyCode ::W = > Some ( InputInstruction ::MoveForward ( s ) ) ,
winit ::event ::VirtualKeyCode ::A = > Some ( InputInstruction ::MoveLeft ( s ) ) ,
winit ::event ::VirtualKeyCode ::S = > Some ( InputInstruction ::MoveBack ( s ) ) ,
winit ::event ::VirtualKeyCode ::D = > Some ( InputInstruction ::MoveRight ( s ) ) ,
winit ::event ::VirtualKeyCode ::E = > Some ( InputInstruction ::MoveUp ( s ) ) ,
winit ::event ::VirtualKeyCode ::Q = > Some ( InputInstruction ::MoveDown ( s ) ) ,
winit ::event ::VirtualKeyCode ::Space = > Some ( InputInstruction ::Jump ( s ) ) ,
winit ::event ::VirtualKeyCode ::Z = > Some ( InputInstruction ::Zoom ( s ) ) ,
winit ::event ::VirtualKeyCode ::R = > if s { Some ( InputInstruction ::Reset ) } else { None } ,
_ = > None ,
} {
self . physics_thread . send ( TimedInstruction {
time ,
instruction :input_instruction ,
} ) . unwrap ( ) ;
}
} ,
_ = > ( ) ,
2023-09-20 00:53:29 +00:00
}
} ,
2023-10-01 22:54:50 +00:00
_ = > ( ) ,
}
}
fn device_event ( & mut self , window : & winit ::window ::Window , event : winit ::event ::DeviceEvent ) {
//there's no way this is the best way get a timestamp.
2023-09-27 09:12:20 +00:00
let time = integer ::Time ::from_nanos ( self . start_time . elapsed ( ) . as_nanos ( ) as i64 ) ;
2023-10-01 22:54:50 +00:00
match event {
2023-09-20 00:53:29 +00:00
winit ::event ::DeviceEvent ::MouseMotion {
delta , //these (f64,f64) are integers on my machine
2023-09-06 21:39:44 +00:00
} = > {
2023-10-02 09:40:36 +00:00
if self . manual_mouse_lock {
2023-10-05 03:04:04 +00:00
match window . set_cursor_position ( winit ::dpi ::PhysicalPosition ::new ( self . graphics . camera . screen_size . x as f32 / 2.0 , self . graphics . camera . screen_size . y as f32 / 2.0 ) ) {
2023-10-02 09:40:36 +00:00
Ok ( ( ) ) = > ( ) ,
Err ( e ) = > println! ( " Could not set cursor position: {:?} " , e ) ,
}
}
2023-09-20 00:53:29 +00:00
//do not step the physics because the mouse polling rate is higher than the physics can run.
//essentially the previous input will be overwritten until a true step runs
//which is fine because they run all the time.
2023-10-05 03:04:04 +00:00
let delta = glam ::ivec2 ( delta . 0 as i32 , delta . 1 as i32 ) ;
self . mouse . pos + = delta ;
self . physics_thread . send ( TimedInstruction {
2023-09-20 00:53:29 +00:00
time ,
2023-10-05 03:04:04 +00:00
instruction :InputInstruction ::MoveMouse ( self . mouse . pos ) ,
} ) . unwrap ( ) ;
2023-09-20 00:53:29 +00:00
} ,
winit ::event ::DeviceEvent ::MouseWheel {
delta ,
} = > {
2023-10-02 10:03:07 +00:00
println! ( " mousewheel {:?} " , delta ) ;
2023-10-01 22:54:24 +00:00
if false { //self.physics.style.use_scroll{
2023-10-05 03:04:04 +00:00
self . physics_thread . send ( TimedInstruction {
2023-09-20 00:53:29 +00:00
time ,
2023-10-05 03:04:04 +00:00
instruction :InputInstruction ::Jump ( true ) , //activates the immediate jump path, but the style modifier prevents controls&CONTROL_JUMP bit from being set to auto jump
} ) . unwrap ( ) ;
2023-09-06 21:39:44 +00:00
}
}
2023-09-20 00:53:29 +00:00
_ = > ( ) ,
2023-09-06 21:39:44 +00:00
}
}
2023-08-30 01:20:58 +00:00
}
2023-07-14 23:49:01 +00:00
fn main ( ) {
2023-10-04 02:43:41 +00:00
framework ::run ::< GlobalState > (
2023-09-06 21:39:44 +00:00
format! ( " Strafe Client v {} " ,
env! ( " CARGO_PKG_VERSION " )
) . as_str ( )
) ;
2023-08-30 01:20:58 +00:00
}