Compare commits

...

11 Commits

Author SHA1 Message Date
fb3869b64e outrageous resize hack 2025-01-03 21:43:40 -08:00
f8583702be use existing canvas 2025-01-03 20:53:44 -08:00
275373d9bc my size 2025-01-03 19:35:27 -08:00
48e68d76a4 cap size to work around loop resize bug 2025-01-03 18:51:50 -08:00
66d4f100c6 use chrono instead of std::time 2025-01-03 18:42:46 -08:00
86d6f7c6a7 pick up wasm dep 2025-01-03 17:46:14 -08:00
3c78d9c94c color functions 2025-01-03 17:45:57 -08:00
e8da9d2a72 attach canvas 2025-01-03 06:45:03 -08:00
2f422e97dd replace enumerate_adapters with request_adapter 2025-01-03 06:45:03 -08:00
eb004cbb21 drop Send requirement 2025-01-03 06:45:03 -08:00
e944e7d91a Initial trunk 2025-01-03 06:45:03 -08:00
9 changed files with 150 additions and 43 deletions

60
Cargo.lock generated
View File

@ -67,6 +67,12 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04"
[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]] [[package]]
name = "android_system_properties" name = "android_system_properties"
version = "0.1.5" version = "0.1.5"
@ -361,6 +367,20 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "chrono"
version = "0.4.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"wasm-bindgen",
"windows-targets 0.52.6",
]
[[package]] [[package]]
name = "codespan-reporting" name = "codespan-reporting"
version = "0.11.1" version = "0.11.1"
@ -781,6 +801,29 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
[[package]]
name = "iana-time-zone"
version = "0.1.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"windows-core 0.52.0",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]] [[package]]
name = "icu_collections" name = "icu_collections"
version = "1.5.0" version = "1.5.0"
@ -2229,6 +2272,7 @@ name = "strafe-client"
version = "0.10.5" version = "0.10.5"
dependencies = [ dependencies = [
"bytemuck", "bytemuck",
"chrono",
"configparser", "configparser",
"ddsfile", "ddsfile",
"glam", "glam",
@ -2240,6 +2284,9 @@ dependencies = [
"strafesnet_deferred_loader", "strafesnet_deferred_loader",
"strafesnet_rbx_loader", "strafesnet_rbx_loader",
"strafesnet_snf", "strafesnet_snf",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"wgpu", "wgpu",
"winit", "winit",
] ]
@ -2891,7 +2938,7 @@ dependencies = [
"web-sys", "web-sys",
"wgpu-types", "wgpu-types",
"windows", "windows",
"windows-core", "windows-core 0.58.0",
] ]
[[package]] [[package]]
@ -2920,7 +2967,16 @@ version = "0.58.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6"
dependencies = [ dependencies = [
"windows-core", "windows-core 0.58.0",
"windows-targets 0.52.6",
]
[[package]]
name = "windows-core"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
dependencies = [
"windows-targets 0.52.6", "windows-targets 0.52.6",
] ]

View File

@ -16,6 +16,7 @@ roblox = ["dep:strafesnet_deferred_loader", "dep:strafesnet_rbx_loader"]
[dependencies] [dependencies]
bytemuck = { version = "1.13.1", features = ["derive"] } bytemuck = { version = "1.13.1", features = ["derive"] }
chrono = "0.4.39"
configparser = "3.0.2" configparser = "3.0.2"
ddsfile = "0.5.1" ddsfile = "0.5.1"
glam = "0.29.0" glam = "0.29.0"
@ -27,5 +28,8 @@ strafesnet_common = { path = "../lib/common", registry = "strafesnet" }
strafesnet_deferred_loader = { path = "../lib/deferred_loader", features = ["legacy"], registry = "strafesnet", optional = true } strafesnet_deferred_loader = { path = "../lib/deferred_loader", features = ["legacy"], registry = "strafesnet", optional = true }
strafesnet_rbx_loader = { path = "../lib/rbx_loader", registry = "strafesnet", optional = true } strafesnet_rbx_loader = { path = "../lib/rbx_loader", registry = "strafesnet", optional = true }
strafesnet_snf = { path = "../lib/snf", registry = "strafesnet", optional = true } strafesnet_snf = { path = "../lib/snf", registry = "strafesnet", optional = true }
wasm-bindgen = "0.2.99"
wasm-bindgen-futures = "0.4.49"
web-sys = { version = "0.3.76", features = ["console"] }
wgpu = "23.0.1" wgpu = "23.0.1"
winit = "0.30.7" winit = "0.30.7"

View File

@ -3,11 +3,11 @@ pub type INWorker<'a,Task>=CompatNWorker<'a,Task>;
pub struct CompatNWorker<'a,Task>{ pub struct CompatNWorker<'a,Task>{
data:std::marker::PhantomData<Task>, data:std::marker::PhantomData<Task>,
f:Box<dyn FnMut(Task)+Send+'a>, f:Box<dyn FnMut(Task)+'a>,
} }
impl<'a,Task> CompatNWorker<'a,Task>{ impl<'a,Task> CompatNWorker<'a,Task>{
pub fn new(f:impl FnMut(Task)+Send+'a)->CompatNWorker<'a,Task>{ pub fn new(f:impl FnMut(Task)+'a)->CompatNWorker<'a,Task>{
Self{ Self{
data:std::marker::PhantomData, data:std::marker::PhantomData,
f:Box::new(f), f:Box::new(f),

View File

@ -14,6 +14,9 @@ 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 //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
fn print(message:&str){
web_sys::console::log_1(&message.into());
}
pub fn new<'a>( pub fn new<'a>(
mut graphics:crate::graphics::GraphicsState, mut graphics:crate::graphics::GraphicsState,
mut config:wgpu::SurfaceConfiguration, mut config:wgpu::SurfaceConfiguration,
@ -33,13 +36,21 @@ pub fn new<'a>(
} }
Instruction::Render(frame_state)=>{ Instruction::Render(frame_state)=>{
if let Some((size,user_settings))=resize.take(){ if let Some((size,user_settings))=resize.take(){
println!("Resizing to {:?}",size); print(format!("Resizing to {:?}",size).as_str());
let t0=std::time::Instant::now(); //let t0=std::time::Instant::now();
config.width=size.width.max(1); match size{
config.height=size.height.max(1); winit::dpi::PhysicalSize{width:2560,height:1440}=>{
config.width=size.width.clamp(1,2560);
config.height=size.height.clamp(1,1440);
},
_=>{
config.width=size.width.clamp(1,1280);
config.height=size.height.clamp(1,720);
}
}
surface.configure(&device,&config); surface.configure(&device,&config);
graphics.resize(&device,&config,&user_settings); graphics.resize(&device,&config,&user_settings);
println!("Resize took {:?}",t0.elapsed()); //println!("Resize took {:?}",t0.elapsed());
} }
//this has to go deeper somehow //this has to go deeper somehow
let frame=match surface.get_current_texture(){ let frame=match surface.get_current_texture(){

View File

@ -13,5 +13,9 @@ mod physics_worker;
mod graphics_worker; mod graphics_worker;
fn main(){ fn main(){
setup::setup_and_start(format!("Strafe Client v{}",env!("CARGO_PKG_VERSION"))); let title=format!("Strafe Client v{}",env!("CARGO_PKG_VERSION"));
#[cfg(target_arch="wasm32")]
wasm_bindgen_futures::spawn_local(setup::setup_and_start(title));
#[cfg(not(target_arch="wasm32"))]
pollster::block_on(setup::setup_and_start(title));
} }

View File

@ -32,6 +32,16 @@ fn create_window(title:&str,event_loop:&winit::event_loop::EventLoop<()>)->Resul
use winit::platform::windows::WindowBuilderExtWindows; use winit::platform::windows::WindowBuilderExtWindows;
builder=builder.with_no_redirection_bitmap(true); builder=builder.with_no_redirection_bitmap(true);
} }
#[cfg(target_arch="wasm32")]
{
use wasm_bindgen::JsCast;
use winit::platform::web::WindowAttributesExtWebSys;
let canvas=web_sys::window().unwrap()
.document().unwrap()
.get_element_by_id("canvas").unwrap()
.dyn_into::<web_sys::HtmlCanvasElement>().unwrap();
attr=attr.with_canvas(Some(canvas));
}
event_loop.create_window(attr) event_loop.create_window(attr)
} }
fn create_instance()->SetupContextPartial1{ fn create_instance()->SetupContextPartial1{
@ -61,36 +71,18 @@ struct SetupContextPartial2<'a>{
surface:wgpu::Surface<'a>, surface:wgpu::Surface<'a>,
} }
impl<'a> SetupContextPartial2<'a>{ impl<'a> SetupContextPartial2<'a>{
fn pick_adapter(self)->SetupContextPartial3<'a>{ async fn pick_adapter(self)->SetupContextPartial3<'a>{
let adapter; let adapter;
//TODO: prefer adapter that implements optional features //TODO: prefer adapter that implements optional features
//let optional_features=optional_features(); //let optional_features=optional_features();
let required_features=required_features(); let required_features=required_features();
//no helper function smh gotta write it myself let chosen_adapter=self.instance.request_adapter(&wgpu::RequestAdapterOptions{
let adapters=self.instance.enumerate_adapters(self.backends); power_preference:wgpu::PowerPreference::HighPerformance,
force_fallback_adapter:false,
let mut chosen_adapter=None; compatible_surface:Some(&self.surface),
let mut chosen_adapter_score=0; }).await;
for adapter in adapters {
if !adapter.is_surface_supported(&self.surface) {
continue;
}
let score=match adapter.get_info().device_type{
wgpu::DeviceType::IntegratedGpu=>3,
wgpu::DeviceType::DiscreteGpu=>4,
wgpu::DeviceType::VirtualGpu=>2,
wgpu::DeviceType::Other|wgpu::DeviceType::Cpu=>1,
};
let adapter_features=adapter.features();
if chosen_adapter_score<score&&adapter_features.contains(required_features) {
chosen_adapter_score=score;
chosen_adapter=Some(adapter);
}
}
if let Some(maybe_chosen_adapter)=chosen_adapter{ if let Some(maybe_chosen_adapter)=chosen_adapter{
adapter=maybe_chosen_adapter; adapter=maybe_chosen_adapter;
@ -129,7 +121,7 @@ struct SetupContextPartial3<'a>{
adapter:wgpu::Adapter, adapter:wgpu::Adapter,
} }
impl<'a> SetupContextPartial3<'a>{ impl<'a> SetupContextPartial3<'a>{
fn request_device(self)->SetupContextPartial4<'a>{ async fn request_device(self)->SetupContextPartial4<'a>{
let optional_features=optional_features(); let optional_features=optional_features();
let required_features=required_features(); let required_features=required_features();
@ -137,7 +129,7 @@ impl<'a> SetupContextPartial3<'a>{
let needed_limits=required_limits().using_resolution(self.adapter.limits()); let needed_limits=required_limits().using_resolution(self.adapter.limits());
let trace_dir=std::env::var("WGPU_TRACE"); let trace_dir=std::env::var("WGPU_TRACE");
let (device, queue)=pollster::block_on(self.adapter let (device, queue)=self.adapter
.request_device( .request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: None, label: None,
@ -146,7 +138,7 @@ impl<'a> SetupContextPartial3<'a>{
memory_hints:wgpu::MemoryHints::Performance, memory_hints:wgpu::MemoryHints::Performance,
}, },
trace_dir.ok().as_ref().map(std::path::Path::new), trace_dir.ok().as_ref().map(std::path::Path::new),
)) ).await
.expect("Unable to find a suitable GPU adapter!"); .expect("Unable to find a suitable GPU adapter!");
SetupContextPartial4{ SetupContextPartial4{
@ -192,7 +184,7 @@ pub struct SetupContext<'a>{
pub config:wgpu::SurfaceConfiguration, pub config:wgpu::SurfaceConfiguration,
} }
pub fn setup_and_start(title:String){ pub async fn setup_and_start(title:String){
let event_loop=winit::event_loop::EventLoop::new().unwrap(); let event_loop=winit::event_loop::EventLoop::new().unwrap();
println!("Initializing the surface..."); println!("Initializing the surface...");
@ -203,9 +195,9 @@ pub fn setup_and_start(title:String){
let partial_2=partial_1.create_surface(&window).unwrap(); let partial_2=partial_1.create_surface(&window).unwrap();
let partial_3=partial_2.pick_adapter(); let partial_3=partial_2.pick_adapter().await;
let partial_4=partial_3.request_device(); let partial_4=partial_3.request_device().await;
let size=window.inner_size(); let size=window.inner_size();
@ -228,17 +220,17 @@ pub fn setup_and_start(title:String){
}; };
println!("Entering event loop..."); println!("Entering event loop...");
let root_time=std::time::Instant::now(); let root_time=chrono::Utc::now();
run_event_loop(event_loop,window_thread,root_time).unwrap(); run_event_loop(event_loop,window_thread,root_time).unwrap();
} }
fn run_event_loop( fn run_event_loop(
event_loop:winit::event_loop::EventLoop<()>, event_loop:winit::event_loop::EventLoop<()>,
mut window_thread:crate::compat_worker::QNWorker<TimedInstruction<WindowInstruction>>, mut window_thread:crate::compat_worker::QNWorker<TimedInstruction<WindowInstruction>>,
root_time:std::time::Instant root_time:chrono::DateTime<chrono::Utc>,
)->Result<(),winit::error::EventLoopError>{ )->Result<(),winit::error::EventLoopError>{
event_loop.run(move |event,elwt|{ event_loop.run(move |event,elwt|{
let time=integer::Time::from_nanos(root_time.elapsed().as_nanos() as i64); let time=integer::Time::from_nanos((chrono::Utc::now()-root_time).num_nanoseconds().unwrap());
// *control_flow=if cfg!(feature="metal-auto-capture"){ // *control_flow=if cfg!(feature="metal-auto-capture"){
// winit::event_loop::ControlFlow::Exit // winit::event_loop::ControlFlow::Exit
// }else{ // }else{

1
web-client/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/dist

2
web-client/Trunk.toml Normal file
View File

@ -0,0 +1,2 @@
[build]
target = "index.html"

37
web-client/index.html Normal file
View File

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Strafe Client</title>
<base data-trunk-public-url />
<style type="text/css">
body {
margin: 0px;
background: #fff;
width: 100%;
height: 100%;
}
.root {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.main-canvas {
margin: 0;
/* This allows the flexbox to grow to max size, this is needed for WebGPU */
flex: 1;
/* This forces CSS to ignore the width/height of the canvas, this is needed for WebGL */
contain: size;
}
</style>
</head>
<body>
<div class="root">
<canvas class="main-canvas" id="canvas"></canvas>
</div>
<link data-trunk rel="rust" href="../strafe-client/Cargo.toml"/>
</body>
</html>