Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
8ab8776916 | |||
5cff2229be | |||
b731ff2ad3 | |||
da8489fad5 | |||
199c96abca | |||
30b2a92c2a | |||
375bbd4aa5 | |||
9800992b67 | |||
61a86a78f4 | |||
da2c246bec | |||
2bcf3cf75d | |||
4a980d44cc | |||
280e2ab58b | |||
16cd673829 |
400
Cargo.lock
generated
400
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -16,6 +16,7 @@ source = ["dep:strafesnet_deferred_loader", "dep:strafesnet_bsp_loader"]
|
|||||||
roblox = ["dep:strafesnet_deferred_loader", "dep:strafesnet_rbx_loader"]
|
roblox = ["dep:strafesnet_deferred_loader", "dep:strafesnet_rbx_loader"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
chrono = "0.4.39"
|
||||||
glam = "0.30.0"
|
glam = "0.30.0"
|
||||||
parking_lot = "0.12.1"
|
parking_lot = "0.12.1"
|
||||||
pollster = "0.4.0"
|
pollster = "0.4.0"
|
||||||
@ -28,5 +29,8 @@ strafesnet_rbx_loader = { path = "../lib/rbx_loader", registry = "strafesnet", o
|
|||||||
strafesnet_session = { path = "../engine/session", registry = "strafesnet" }
|
strafesnet_session = { path = "../engine/session", registry = "strafesnet" }
|
||||||
strafesnet_settings = { path = "../engine/settings", registry = "strafesnet" }
|
strafesnet_settings = { path = "../engine/settings", registry = "strafesnet" }
|
||||||
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 = "24.0.0"
|
wgpu = "24.0.0"
|
||||||
winit = "0.30.7"
|
winit = "0.30.7"
|
||||||
|
@ -4,12 +4,12 @@ use strafesnet_common::instruction::TimedInstruction;
|
|||||||
use strafesnet_common::session::Time as SessionTime;
|
use strafesnet_common::session::Time as SessionTime;
|
||||||
|
|
||||||
pub struct App<'a>{
|
pub struct App<'a>{
|
||||||
root_time:std::time::Instant,
|
root_time:chrono::DateTime<chrono::Utc>,
|
||||||
window_thread:crate::compat_worker::QNWorker<'a,TimedInstruction<Instruction,SessionTime>>,
|
window_thread:crate::compat_worker::QNWorker<'a,TimedInstruction<Instruction,SessionTime>>,
|
||||||
}
|
}
|
||||||
impl<'a> App<'a>{
|
impl<'a> App<'a>{
|
||||||
pub fn new(
|
pub fn new(
|
||||||
root_time:std::time::Instant,
|
root_time:chrono::DateTime<chrono::Utc>,
|
||||||
window_thread:crate::compat_worker::QNWorker<'a,TimedInstruction<Instruction,SessionTime>>,
|
window_thread:crate::compat_worker::QNWorker<'a,TimedInstruction<Instruction,SessionTime>>,
|
||||||
)->App<'a>{
|
)->App<'a>{
|
||||||
Self{
|
Self{
|
||||||
@ -18,7 +18,7 @@ impl<'a> App<'a>{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn send_timed_instruction(&mut self,instruction:Instruction){
|
fn send_timed_instruction(&mut self,instruction:Instruction){
|
||||||
let time=integer::Time::from_nanos(self.root_time.elapsed().as_nanos() as i64);
|
let time=integer::Time::from_nanos((chrono::Utc::now()-self.root_time).num_nanoseconds().unwrap());
|
||||||
self.window_thread.send(TimedInstruction{time,instruction}).unwrap();
|
self.window_thread.send(TimedInstruction{time,instruction}).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
|
@ -18,6 +18,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(
|
pub fn new(
|
||||||
mut graphics:graphics::GraphicsState,
|
mut graphics:graphics::GraphicsState,
|
||||||
mut config:wgpu::SurfaceConfiguration,
|
mut config:wgpu::SurfaceConfiguration,
|
||||||
@ -33,12 +36,20 @@ pub fn new(
|
|||||||
},
|
},
|
||||||
Instruction::Resize(size,user_settings)=>{
|
Instruction::Resize(size,user_settings)=>{
|
||||||
println!("Resizing to {:?}",size);
|
println!("Resizing to {:?}",size);
|
||||||
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());
|
||||||
}
|
}
|
||||||
Instruction::Render(frame_state)=>{
|
Instruction::Render(frame_state)=>{
|
||||||
//this has to go deeper somehow
|
//this has to go deeper somehow
|
||||||
|
@ -9,5 +9,8 @@ mod graphics_worker;
|
|||||||
const TITLE:&'static str=concat!("Strafe Client v",env!("CARGO_PKG_VERSION"));
|
const TITLE:&'static str=concat!("Strafe Client v",env!("CARGO_PKG_VERSION"));
|
||||||
|
|
||||||
fn main(){
|
fn main(){
|
||||||
setup::setup_and_start(TITLE);
|
#[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));
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,16 @@ struct SetupContextPartial1{
|
|||||||
fn create_window(title:&str,event_loop:&winit::event_loop::EventLoop<()>)->Result<winit::window::Window,winit::error::OsError>{
|
fn create_window(title:&str,event_loop:&winit::event_loop::EventLoop<()>)->Result<winit::window::Window,winit::error::OsError>{
|
||||||
let mut attr=winit::window::WindowAttributes::default();
|
let mut attr=winit::window::WindowAttributes::default();
|
||||||
attr=attr.with_title(title);
|
attr=attr.with_title(title);
|
||||||
|
#[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{
|
||||||
@ -44,36 +54,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;
|
||||||
@ -110,7 +102,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();
|
||||||
|
|
||||||
@ -118,7 +110,7 @@ impl<'a> SetupContextPartial3<'a>{
|
|||||||
let needed_limits=strafesnet_graphics::graphics::required_limits().using_resolution(self.adapter.limits());
|
let needed_limits=strafesnet_graphics::graphics::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,
|
||||||
@ -127,7 +119,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{
|
||||||
@ -169,7 +161,7 @@ pub struct SetupContext<'a>{
|
|||||||
pub config:wgpu::SurfaceConfiguration,
|
pub config:wgpu::SurfaceConfiguration,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setup_and_start(title:&str){
|
pub async fn setup_and_start(title:&str){
|
||||||
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...");
|
||||||
@ -180,9 +172,9 @@ pub fn setup_and_start(title:&str){
|
|||||||
|
|
||||||
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();
|
||||||
|
|
||||||
@ -205,7 +197,7 @@ pub fn setup_and_start(title:&str){
|
|||||||
|
|
||||||
println!("Entering event loop...");
|
println!("Entering event loop...");
|
||||||
let mut app=crate::app::App::new(
|
let mut app=crate::app::App::new(
|
||||||
std::time::Instant::now(),
|
chrono::Utc::now(),
|
||||||
window_thread
|
window_thread
|
||||||
);
|
);
|
||||||
event_loop.run_app(&mut app).unwrap();
|
event_loop.run_app(&mut app).unwrap();
|
||||||
|
1
web-client/.gitignore
vendored
Normal file
1
web-client/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/dist
|
2
web-client/Trunk.toml
Normal file
2
web-client/Trunk.toml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[build]
|
||||||
|
target = "index.html"
|
35
web-client/index.html
Normal file
35
web-client/index.html
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Strafe Client</title>
|
||||||
|
<style>
|
||||||
|
html, body {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
#wasm-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
canvas {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="wasm-container">
|
||||||
|
<canvas class="main-canvas" id="canvas"></canvas>
|
||||||
|
</div>
|
||||||
|
<link data-trunk rel="rust" href="../strafe-client/Cargo.toml"/>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
x
Reference in New Issue
Block a user