Compare commits
1 Commits
zero-verti
...
minterp-bu
| Author | SHA1 | Date | |
|---|---|---|---|
|
e053139ffb
|
505
Cargo.lock
generated
505
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
19
Cargo.toml
19
Cargo.toml
@@ -35,22 +35,3 @@ unused_lifetimes = "warn"
|
||||
unused_qualifications = "warn"
|
||||
# variant_size_differences = "warn"
|
||||
unexpected_cfgs = "warn"
|
||||
|
||||
[workspace.dependencies]
|
||||
glam = "0.31.0"
|
||||
|
||||
# engine
|
||||
strafesnet_graphics = { path = "engine/graphics", registry = "strafesnet" }
|
||||
strafesnet_physics = { version = "0.0.1", path = "engine/physics", registry = "strafesnet" }
|
||||
strafesnet_session = { path = "engine/session", registry = "strafesnet" }
|
||||
strafesnet_settings = { path = "engine/settings", registry = "strafesnet" }
|
||||
|
||||
# lib
|
||||
fixed_wide = { version = "0.2.2", path = "lib/fixed_wide", registry = "strafesnet" }
|
||||
linear_ops = { version = "0.1.1", path = "lib/linear_ops", registry = "strafesnet" }
|
||||
ratio_ops = { version = "0.1.0", path = "lib/ratio_ops", registry = "strafesnet" }
|
||||
strafesnet_bsp_loader = { path = "lib/bsp_loader", registry = "strafesnet" }
|
||||
strafesnet_common = { version = "0.8.5", path = "lib/common", registry = "strafesnet" }
|
||||
strafesnet_deferred_loader = { version = "0.5.1", path = "lib/deferred_loader", registry = "strafesnet" }
|
||||
strafesnet_rbx_loader = { path = "lib/rbx_loader", registry = "strafesnet" }
|
||||
strafesnet_snf = { version = "0.3.2", path = "lib/snf", registry = "strafesnet" }
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
[package]
|
||||
name = "strafesnet_graphics"
|
||||
version = "0.0.2"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
bytemuck = { version = "1.13.1", features = ["derive"] }
|
||||
ddsfile = "0.5.1"
|
||||
glam.workspace = true
|
||||
glam = "0.30.0"
|
||||
id = { version = "0.1.0", registry = "strafesnet" }
|
||||
strafesnet_common.workspace = true
|
||||
strafesnet_common = { path = "../../lib/common", registry = "strafesnet" }
|
||||
strafesnet_session = { path = "../session", registry = "strafesnet" }
|
||||
strafesnet_settings = { path = "../settings", registry = "strafesnet" }
|
||||
wgpu = "28.0.0"
|
||||
|
||||
[lints]
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use std::borrow::Cow;
|
||||
use std::collections::{HashSet,HashMap};
|
||||
use strafesnet_common::map;
|
||||
use strafesnet_settings::settings;
|
||||
use strafesnet_session::session;
|
||||
use strafesnet_common::model::{self, ColorId, NormalId, PolygonIter, PositionId, RenderConfigId, TextureCoordinateId, VertexId};
|
||||
use wgpu::{util::DeviceExt,AstcBlock,AstcChannel};
|
||||
use crate::model::{self as model_graphics,IndexedGraphicsMeshOwnedRenderConfig,IndexedGraphicsMeshOwnedRenderConfigId,GraphicsMeshOwnedRenderConfig,GraphicsModelColor4,GraphicsModelOwned,GraphicsVertex};
|
||||
@@ -52,10 +54,6 @@ struct GraphicsPipelines{
|
||||
model:wgpu::RenderPipeline,
|
||||
}
|
||||
|
||||
pub fn view_inv(pos:glam::Vec3,angles:glam::Vec2)->glam::Mat4{
|
||||
//f32 good enough for view matrix
|
||||
glam::Mat4::from_mat3_translation(glam::Mat3::from_euler(glam::EulerRot::YXZ,angles.x,angles.y,0f32),pos)
|
||||
}
|
||||
struct GraphicsCamera{
|
||||
screen_size:glam::UVec2,
|
||||
fov:glam::Vec2,//slope
|
||||
@@ -77,10 +75,15 @@ impl GraphicsCamera{
|
||||
pub fn proj(&self)->glam::Mat4{
|
||||
perspective_rh(self.fov.x,self.fov.y,0.4,4000.0)
|
||||
}
|
||||
pub fn world(&self,pos:glam::Vec3,angles:glam::Vec2)->glam::Mat4{
|
||||
//f32 good enough for view matrix
|
||||
glam::Mat4::from_translation(pos)*glam::Mat4::from_euler(glam::EulerRot::YXZ,angles.x,angles.y,0f32)
|
||||
}
|
||||
|
||||
pub fn to_uniform_data(&self,view_inv:glam::Mat4)->[f32;16*4]{
|
||||
pub fn to_uniform_data(&self,pos:glam::Vec3,angles:glam::Vec2)->[f32;16*4]{
|
||||
let proj=self.proj();
|
||||
let proj_inv=proj.inverse();
|
||||
let view_inv=self.world(pos,angles);
|
||||
let view=view_inv.inverse();
|
||||
|
||||
let mut raw=[0f32; 16 * 4];
|
||||
@@ -159,6 +162,9 @@ impl GraphicsState{
|
||||
pub fn clear(&mut self){
|
||||
self.models.clear();
|
||||
}
|
||||
pub fn load_user_settings(&mut self,user_settings:&settings::UserSettings){
|
||||
self.camera.fov=user_settings.calculate_fov(1.0,&self.camera.screen_size).as_vec2();
|
||||
}
|
||||
pub fn generate_models(&mut self,device:&wgpu::Device,queue:&wgpu::Queue,map:&map::CompleteMap){
|
||||
//generate texture view per texture
|
||||
let texture_views:HashMap<model::TextureId,wgpu::TextureView>=map.textures.iter().enumerate().filter_map(|(texture_id,texture_data)|{
|
||||
@@ -628,7 +634,7 @@ impl GraphicsState{
|
||||
// Create the render pipeline
|
||||
let shader=device.create_shader_module(wgpu::ShaderModuleDescriptor{
|
||||
label:None,
|
||||
source:wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("../shaders/shader.wgsl"))),
|
||||
source:wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("../../../strafe-client/src/shader.wgsl"))),
|
||||
});
|
||||
|
||||
//load textures
|
||||
@@ -656,10 +662,10 @@ impl GraphicsState{
|
||||
wgpu::TextureFormat::Astc{
|
||||
block:AstcBlock::B4x4,
|
||||
channel:AstcChannel::UnormSrgb,
|
||||
}=>&include_bytes!("../images/astc.dds")[..],
|
||||
wgpu::TextureFormat::Etc2Rgb8UnormSrgb=>&include_bytes!("../images/etc2.dds")[..],
|
||||
wgpu::TextureFormat::Bc1RgbaUnormSrgb=>&include_bytes!("../images/bc1.dds")[..],
|
||||
wgpu::TextureFormat::Bgra8UnormSrgb=>&include_bytes!("../images/bgra.dds")[..],
|
||||
}=>&include_bytes!("../../../strafe-client/images/astc.dds")[..],
|
||||
wgpu::TextureFormat::Etc2Rgb8UnormSrgb=>&include_bytes!("../../../strafe-client/images/etc2.dds")[..],
|
||||
wgpu::TextureFormat::Bc1RgbaUnormSrgb=>&include_bytes!("../../../strafe-client/images/bc1.dds")[..],
|
||||
wgpu::TextureFormat::Bgra8UnormSrgb=>&include_bytes!("../../../strafe-client/images/bgra.dds")[..],
|
||||
_=>unreachable!(),
|
||||
};
|
||||
|
||||
@@ -702,7 +708,7 @@ impl GraphicsState{
|
||||
|
||||
//squid
|
||||
let squid_texture_view={
|
||||
let bytes=include_bytes!("../images/squid.dds");
|
||||
let bytes=include_bytes!("../../../strafe-client/images/squid.dds");
|
||||
|
||||
let image=ddsfile::Dds::read(&mut std::io::Cursor::new(bytes)).unwrap();
|
||||
|
||||
@@ -827,7 +833,7 @@ impl GraphicsState{
|
||||
});
|
||||
|
||||
let camera=GraphicsCamera::default();
|
||||
let camera_uniforms=camera.to_uniform_data(view_inv(glam::Vec3::ZERO,glam::Vec2::ZERO));
|
||||
let camera_uniforms=camera.to_uniform_data(glam::Vec3::ZERO,glam::Vec2::ZERO);
|
||||
let camera_buf=device.create_buffer_init(&wgpu::util::BufferInitDescriptor{
|
||||
label:Some("Camera"),
|
||||
contents:bytemuck::cast_slice(&camera_uniforms),
|
||||
@@ -884,25 +890,28 @@ impl GraphicsState{
|
||||
&mut self,
|
||||
device:&wgpu::Device,
|
||||
config:&wgpu::SurfaceConfiguration,
|
||||
fov:glam::Vec2,
|
||||
user_settings:&settings::UserSettings,
|
||||
){
|
||||
self.depth_view=Self::create_depth_texture(config,device);
|
||||
self.camera.screen_size=glam::uvec2(config.width,config.height);
|
||||
self.camera.fov=fov;
|
||||
self.load_user_settings(user_settings);
|
||||
}
|
||||
pub fn render(
|
||||
&mut self,
|
||||
view:&wgpu::TextureView,
|
||||
device:&wgpu::Device,
|
||||
queue:&wgpu::Queue,
|
||||
camera:glam::Mat4,
|
||||
frame_state:session::FrameState,
|
||||
){
|
||||
//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(camera);
|
||||
let camera_uniforms=self.camera.to_uniform_data(
|
||||
frame_state.trajectory.extrapolated_position(frame_state.time).map(Into::<f32>::into).to_array().into(),
|
||||
frame_state.camera.simulate_move_angles(glam::IVec2::ZERO)
|
||||
);
|
||||
self.staging_belt
|
||||
.write_buffer(
|
||||
&mut encoder,
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
pub mod model;
|
||||
pub mod setup;
|
||||
pub mod graphics;
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
fn optional_features()->wgpu::Features{
|
||||
wgpu::Features::TEXTURE_COMPRESSION_ASTC
|
||||
|wgpu::Features::TEXTURE_COMPRESSION_ETC2
|
||||
}
|
||||
fn required_features()->wgpu::Features{
|
||||
wgpu::Features::TEXTURE_COMPRESSION_BC
|
||||
}
|
||||
fn required_downlevel_capabilities()->wgpu::DownlevelCapabilities{
|
||||
wgpu::DownlevelCapabilities{
|
||||
flags:wgpu::DownlevelFlags::empty(),
|
||||
shader_model:wgpu::ShaderModel::Sm5,
|
||||
..wgpu::DownlevelCapabilities::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub mod step1{
|
||||
pub fn create_instance()->wgpu::Instance{
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub mod step2{
|
||||
pub fn create_surface<'window>(instance:&wgpu::Instance,target:impl Into<wgpu::SurfaceTarget<'window>>)->Result<wgpu::Surface<'window>,wgpu::CreateSurfaceError>{
|
||||
instance.create_surface(target)
|
||||
}
|
||||
}
|
||||
|
||||
pub mod step3{
|
||||
pub async fn pick_adapter(instance:&wgpu::Instance,surface:&wgpu::Surface<'_>)->Option<wgpu::Adapter>{
|
||||
let backends=wgpu::Backends::from_env().unwrap_or_default();
|
||||
//TODO: prefer adapter that implements optional features
|
||||
//let optional_features=optional_features();
|
||||
let required_features=super::required_features();
|
||||
let required_downlevel_capabilities=super::required_downlevel_capabilities();
|
||||
|
||||
//no helper function smh gotta write it myself
|
||||
let adapters=instance.enumerate_adapters(backends).await;
|
||||
|
||||
let adapter=adapters.into_iter()
|
||||
// reverse because we want to select adapters that appear first in ties,
|
||||
// and max_by_key selects the last equal element in the iterator.
|
||||
.rev()
|
||||
.filter(|adapter|
|
||||
adapter.is_surface_supported(surface)
|
||||
&&adapter.features().contains(required_features)
|
||||
&&{
|
||||
let downlevel_capabilities=adapter.get_downlevel_capabilities();
|
||||
downlevel_capabilities.shader_model>=required_downlevel_capabilities.shader_model
|
||||
&&downlevel_capabilities.flags.contains(required_downlevel_capabilities.flags)
|
||||
}
|
||||
)
|
||||
.max_by_key(|adapter|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_info=adapter.get_info();
|
||||
println!("Using {} ({:?})", adapter_info.name, adapter_info.backend);
|
||||
|
||||
Some(adapter)
|
||||
}
|
||||
}
|
||||
|
||||
pub mod step4{
|
||||
pub async fn request_device(adapter:&wgpu::Adapter)->(wgpu::Device,wgpu::Queue){
|
||||
let optional_features=super::optional_features();
|
||||
let required_features=super::required_features();
|
||||
|
||||
// Make sure we use the texture resolution limits from the adapter, so we can support images the size of the surface.
|
||||
let needed_limits=crate::graphics::required_limits().using_resolution(adapter.limits());
|
||||
|
||||
let (device, queue)=adapter
|
||||
.request_device(
|
||||
&wgpu::DeviceDescriptor{
|
||||
label:None,
|
||||
required_features:(optional_features&adapter.features())|required_features,
|
||||
required_limits:needed_limits,
|
||||
memory_hints:wgpu::MemoryHints::Performance,
|
||||
trace:wgpu::Trace::Off,
|
||||
experimental_features:wgpu::ExperimentalFeatures::disabled(),
|
||||
},
|
||||
).await
|
||||
.expect("Unable to find a suitable GPU adapter!");
|
||||
|
||||
(
|
||||
device,
|
||||
queue,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub mod step5{
|
||||
pub fn configure_surface(
|
||||
adapter:&wgpu::Adapter,
|
||||
device:&wgpu::Device,
|
||||
surface:&wgpu::Surface<'_>,
|
||||
(width,height):(u32,u32),
|
||||
)->wgpu::SurfaceConfiguration{
|
||||
let mut config=surface
|
||||
.get_default_config(adapter, width, height)
|
||||
.expect("Surface isn't supported by the adapter.");
|
||||
|
||||
let surface_view_format=config.format.add_srgb_suffix();
|
||||
config.view_formats.push(surface_view_format);
|
||||
config.present_mode=wgpu::PresentMode::AutoNoVsync;
|
||||
surface.configure(device,&config);
|
||||
|
||||
config
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
[package]
|
||||
name = "strafesnet_physics"
|
||||
version = "0.0.1"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
arrayvec = "0.7.6"
|
||||
glam.workspace = true
|
||||
glam = "0.30.0"
|
||||
id = { version = "0.1.0", registry = "strafesnet" }
|
||||
strafesnet_common.workspace = true
|
||||
strafesnet_common = { path = "../../lib/common", registry = "strafesnet" }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -268,12 +268,6 @@ pub struct PhysicsCamera{
|
||||
impl PhysicsCamera{
|
||||
const ANGLE_PITCH_LOWER_LIMIT:Angle32=Angle32::NEG_FRAC_PI_2;
|
||||
const ANGLE_PITCH_UPPER_LIMIT:Angle32=Angle32::FRAC_PI_2;
|
||||
fn set_sensitivity(&mut self,sensitivity:Ratio64Vec2){
|
||||
// Calculate nearest mouse position in new sensitivity
|
||||
self.clamped_mouse_pos.x=(self.clamped_mouse_pos.x as i128*self.sensitivity.x.num() as i128*sensitivity.x.den() as i128/(sensitivity.x.num() as i128*self.sensitivity.x.den() as i128)) as i32;
|
||||
self.clamped_mouse_pos.y=(self.clamped_mouse_pos.y as i128*self.sensitivity.y.num() as i128*sensitivity.y.den() as i128/(sensitivity.y.num() as i128*self.sensitivity.y.den() as i128)) as i32;
|
||||
self.sensitivity=sensitivity;
|
||||
}
|
||||
pub fn move_mouse(&mut self,mouse_delta:glam::IVec2){
|
||||
let mut unclamped_mouse_pos=self.clamped_mouse_pos+mouse_delta;
|
||||
unclamped_mouse_pos.y=unclamped_mouse_pos.y.clamp(
|
||||
@@ -1883,7 +1877,7 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI
|
||||
state.camera.move_mouse(m0.pos-state.input_state.next_mouse.pos);
|
||||
state.input_state.replace_mouse(m0,m1);
|
||||
},
|
||||
Instruction::Misc(MiscInstruction::SetSensitivity(sensitivity))=>state.camera.set_sensitivity(sensitivity),
|
||||
Instruction::Misc(MiscInstruction::SetSensitivity(sensitivity))=>state.camera.sensitivity=sensitivity,
|
||||
Instruction::SetControl(SetControlInstruction::SetMoveForward(s))=>state.input_state.set_control(Controls::MoveForward,s),
|
||||
Instruction::SetControl(SetControlInstruction::SetMoveLeft(s))=>state.input_state.set_control(Controls::MoveLeft,s),
|
||||
Instruction::SetControl(SetControlInstruction::SetMoveBack(s))=>state.input_state.set_control(Controls::MoveBackward,s),
|
||||
|
||||
@@ -4,12 +4,12 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
glam.workspace = true
|
||||
glam = "0.30.0"
|
||||
replace_with = "0.1.7"
|
||||
strafesnet_common.workspace = true
|
||||
strafesnet_physics.workspace = true
|
||||
strafesnet_settings.workspace = true
|
||||
strafesnet_snf.workspace = true
|
||||
strafesnet_common = { path = "../../lib/common", registry = "strafesnet" }
|
||||
strafesnet_physics = { path = "../physics", registry = "strafesnet" }
|
||||
strafesnet_settings = { path = "../settings", registry = "strafesnet" }
|
||||
strafesnet_snf = { path = "../../lib/snf", registry = "strafesnet" }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -138,6 +138,7 @@ impl MouseInterpolator{
|
||||
match buffer_state{
|
||||
BufferState::Unbuffered=>(),
|
||||
BufferState::Initializing(_time,mouse_state)=>{
|
||||
println!("{timeout_time} Time out Initializing");
|
||||
// only a single mouse move was sent in 10ms, this is very much an edge case!
|
||||
self.push_mouse_and_flush_buffer(TimedInstruction{
|
||||
time:mouse_state.time,
|
||||
@@ -148,6 +149,7 @@ impl MouseInterpolator{
|
||||
});
|
||||
}
|
||||
BufferState::Buffered(_time,mouse_state)=>{
|
||||
println!("{timeout_time} Time out Buffered");
|
||||
// duplicate the currently buffered mouse state but at a later (future, from the physics perspective) time
|
||||
self.push_mouse_and_flush_buffer(TimedInstruction{
|
||||
time:mouse_state.time,
|
||||
@@ -157,6 +159,7 @@ impl MouseInterpolator{
|
||||
}
|
||||
}
|
||||
fn push_unbuffered_input(&mut self,session_time:SessionTime,physics_time:PhysicsTime,ins:UnbufferedInstruction){
|
||||
println!("helo");
|
||||
// new input
|
||||
// if there is zero instruction buffered, it means the mouse is not moving
|
||||
// case 1: unbuffered
|
||||
@@ -177,9 +180,11 @@ impl MouseInterpolator{
|
||||
let next_mouse_state=MouseState{pos,time:physics_time};
|
||||
match buffer_state{
|
||||
BufferState::Unbuffered=>{
|
||||
println!("{session_time} Unbuffered -> Initializing");
|
||||
((None,None),BufferState::Initializing(session_time,next_mouse_state))
|
||||
},
|
||||
BufferState::Initializing(_time,mouse_state)=>{
|
||||
println!("{session_time} Initializing -> Buffered");
|
||||
let ins_mouse=TimedInstruction{
|
||||
time:mouse_state.time,
|
||||
instruction:MouseInstruction::ReplaceMouse{
|
||||
@@ -190,6 +195,7 @@ impl MouseInterpolator{
|
||||
((Some(ins_mouse),None),BufferState::Buffered(session_time,next_mouse_state))
|
||||
},
|
||||
BufferState::Buffered(_time,mouse_state)=>{
|
||||
println!("{session_time} Buffered");
|
||||
let ins_mouse=TimedInstruction{
|
||||
time:mouse_state.time,
|
||||
instruction:MouseInstruction::SetNextMouse(next_mouse_state.clone()),
|
||||
|
||||
@@ -61,14 +61,6 @@ pub struct FrameState{
|
||||
pub camera:physics::PhysicsCamera,
|
||||
pub time:PhysicsTime,
|
||||
}
|
||||
impl FrameState{
|
||||
pub fn pos(&self)->glam::Vec3{
|
||||
self.trajectory.extrapolated_position(self.time).map(Into::<f32>::into).to_array().into()
|
||||
}
|
||||
pub fn angles(&self)->glam::Vec2{
|
||||
self.camera.simulate_move_angles(glam::IVec2::ZERO)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Simulation{
|
||||
timer:Timer<Scaled<SessionTimeInner,PhysicsTimeInner>>,
|
||||
@@ -229,6 +221,7 @@ impl InstructionConsumer<Instruction<'_>> for Session{
|
||||
};
|
||||
}
|
||||
|
||||
println!("=== PRE-PROCESS ===");
|
||||
// process any timeouts that occured since the last instruction
|
||||
self.process_exhaustive(ins.time);
|
||||
|
||||
@@ -430,6 +423,7 @@ impl InstructionConsumer<Instruction<'_>> for Session{
|
||||
}
|
||||
};
|
||||
|
||||
println!("=== POST-PROCESS ===");
|
||||
// process all emitted output instructions
|
||||
self.process_exhaustive(ins.time);
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ edition = "2024"
|
||||
[dependencies]
|
||||
configparser = "3.0.2"
|
||||
directories = "6.0.0"
|
||||
glam.workspace = true
|
||||
strafesnet_common.workspace = true
|
||||
glam = "0.30.0"
|
||||
strafesnet_common = { path = "../../lib/common", registry = "strafesnet" }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -4,12 +4,12 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
glam.workspace = true
|
||||
strafesnet_common.workspace = true
|
||||
strafesnet_physics.workspace = true
|
||||
strafesnet_snf.workspace = true
|
||||
glam = "0.30.0"
|
||||
strafesnet_common = { path = "../lib/common", registry = "strafesnet" }
|
||||
strafesnet_physics = { path = "../engine/physics", registry = "strafesnet" }
|
||||
strafesnet_snf = { path = "../lib/snf", registry = "strafesnet" }
|
||||
# this is just for the primitive constructor
|
||||
strafesnet_rbx_loader.workspace = true
|
||||
strafesnet_rbx_loader = { path = "../lib/rbx_loader", registry = "strafesnet" }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -10,9 +10,9 @@ authors = ["Rhys Lloyd <krakow20@gmail.com>"]
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
glam.workspace = true
|
||||
strafesnet_common.workspace = true
|
||||
strafesnet_deferred_loader.workspace = true
|
||||
glam = "0.30.0"
|
||||
strafesnet_common = { version = "0.7.0", path = "../common", registry = "strafesnet" }
|
||||
strafesnet_deferred_loader = { version = "0.5.1", path = "../deferred_loader", registry = "strafesnet" }
|
||||
vbsp = "0.9.1"
|
||||
vbsp-entities-css = "0.6.0"
|
||||
vmdl = "0.2.0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "strafesnet_common"
|
||||
version = "0.8.5"
|
||||
version = "0.7.0"
|
||||
edition = "2024"
|
||||
repository = "https://git.itzana.me/StrafesNET/strafe-project"
|
||||
license = "MIT OR Apache-2.0"
|
||||
@@ -12,10 +12,10 @@ authors = ["Rhys Lloyd <krakow20@gmail.com>"]
|
||||
[dependencies]
|
||||
arrayvec = "0.7.4"
|
||||
bitflags = "2.6.0"
|
||||
fixed_wide = { workspace = true, features = ["deferred-division","zeroes","wide-mul"] }
|
||||
linear_ops = { workspace = true, features = ["deferred-division","named-fields"] }
|
||||
ratio_ops = { workspace = true }
|
||||
glam.workspace = true
|
||||
fixed_wide = { version = "0.2.0", path = "../fixed_wide", registry = "strafesnet", features = ["deferred-division","zeroes","wide-mul"] }
|
||||
linear_ops = { version = "0.1.1", path = "../linear_ops", registry = "strafesnet", features = ["deferred-division","named-fields"] }
|
||||
ratio_ops = { version = "0.1.0", path = "../ratio_ops", registry = "strafesnet" }
|
||||
glam = "0.30.0"
|
||||
id = { version = "0.1.0", registry = "strafesnet" }
|
||||
|
||||
[lints]
|
||||
|
||||
@@ -56,14 +56,6 @@ impl<T> Time<T>{
|
||||
pub const fn coerce<U>(self)->Time<U>{
|
||||
Time::raw(self.0)
|
||||
}
|
||||
#[inline]
|
||||
pub const fn div_euclid(self,other:Self)->Self{
|
||||
Time::raw(self.0.div_euclid(other.0))
|
||||
}
|
||||
#[inline]
|
||||
pub const fn rem_euclid(self,other:Self)->Self{
|
||||
Time::raw(self.0.rem_euclid(other.0))
|
||||
}
|
||||
}
|
||||
impl<T> From<Planar64> for Time<T>{
|
||||
#[inline]
|
||||
@@ -157,23 +149,10 @@ impl_time_i64_rhs_operator!(Shr,shr);
|
||||
impl_time_i64_rhs_operator!(Shl,shl);
|
||||
impl<T> core::ops::Mul<Time<T>> for Planar64{
|
||||
type Output=Ratio<Fixed<2,64>,Planar64>;
|
||||
#[inline]
|
||||
fn mul(self,rhs:Time<T>)->Self::Output{
|
||||
Ratio::new(self*Fixed::raw(rhs.0),Planar64::raw(1_000_000_000))
|
||||
}
|
||||
}
|
||||
impl<T> From<Time<T>> for f32{
|
||||
#[inline]
|
||||
fn from(value:Time<T>)->Self{
|
||||
value.get() as f32/Time::<T>::ONE_SECOND.get() as f32
|
||||
}
|
||||
}
|
||||
impl<T> From<Time<T>> for f64{
|
||||
#[inline]
|
||||
fn from(value:Time<T>)->Self{
|
||||
value.get() as f64/Time::<T>::ONE_SECOND.get() as f64
|
||||
}
|
||||
}
|
||||
#[cfg(test)]
|
||||
mod test_time{
|
||||
use super::*;
|
||||
@@ -235,11 +214,11 @@ impl Ratio64{
|
||||
}
|
||||
#[inline]
|
||||
pub const fn mul_int(&self,rhs:i64)->i64{
|
||||
(rhs as i128*self.num as i128/self.den as i128) as i64
|
||||
rhs*self.num/(self.den as i64)
|
||||
}
|
||||
#[inline]
|
||||
pub const fn rhs_div_int(&self,rhs:i64)->i64{
|
||||
(rhs as i128*self.den as i128/self.num as i128) as i64
|
||||
rhs*(self.den as i64)/self.num
|
||||
}
|
||||
#[inline]
|
||||
pub const fn mul_ref(&self,rhs:&Ratio64)->Ratio64{
|
||||
@@ -284,6 +263,7 @@ fn integer_decode_f64(f: f64) -> (u64, i16, i8) {
|
||||
pub enum Ratio64TryFromFloatError{
|
||||
Nan,
|
||||
Infinite,
|
||||
Subnormal,
|
||||
HighlyNegativeExponent(i16),
|
||||
HighlyPositiveExponent(i16),
|
||||
}
|
||||
@@ -318,10 +298,8 @@ fn ratio64_from_mes((m,e,s):(u64,i16,i8))->Result<Ratio64,Ratio64TryFromFloatErr
|
||||
|
||||
Ok(Ratio64::new(num as i64,den as u64).unwrap())
|
||||
}else if e<0{
|
||||
// simple exact representation
|
||||
Ok(Ratio64::new((m as i64)*(s as i64),1<<-e).unwrap())
|
||||
}else if (64-m.leading_zeros() as i16)+e<64{
|
||||
// integer
|
||||
Ok(Ratio64::new((m as i64)*(s as i64)*(1<<e),1).unwrap())
|
||||
}else{
|
||||
Err(Ratio64TryFromFloatError::HighlyPositiveExponent(e))
|
||||
@@ -353,29 +331,6 @@ impl TryFrom<f64> for Ratio64{
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(test)]
|
||||
fn req(r0:Ratio64,r1:Ratio64){
|
||||
println!("r0={r0:?} r1={r1:?}");
|
||||
assert_eq!(r0.num(),r1.num(),"Nums not eq");
|
||||
assert_eq!(r0.den(),r1.den(),"Dens not eq");
|
||||
}
|
||||
#[test]
|
||||
fn test_ratio64_from_float(){
|
||||
req(2.0.try_into().unwrap(),Ratio64::new(2,1).unwrap());
|
||||
req(1.0.try_into().unwrap(),Ratio64::new(1,1).unwrap());
|
||||
req(0.5.try_into().unwrap(),Ratio64::new(1,2).unwrap());
|
||||
req(1.1.try_into().unwrap(),Ratio64::new(2476979795053773,2251799813685248).unwrap());
|
||||
req(0.8.try_into().unwrap(),Ratio64::new(3602879701896397,4503599627370496).unwrap());
|
||||
req(0.61.try_into().unwrap(),Ratio64::new(5494391545392005,9007199254740992).unwrap());
|
||||
req(0.01.try_into().unwrap(),Ratio64::new(5764607523034235,576460752303423488).unwrap());
|
||||
req(0.001.try_into().unwrap(),Ratio64::new(1152921504606847,1152921504606846976).unwrap());
|
||||
req(0.00001.try_into().unwrap(),Ratio64::new(89605456633725,8960545663372499267).unwrap());
|
||||
req(0.00000000001.try_into().unwrap(),Ratio64::new(35204848,3520484800000000213).unwrap());
|
||||
req(0.000000000000000001.try_into().unwrap(),Ratio64::new(11,10999999999999999213).unwrap());
|
||||
req(2222222222222.0.try_into().unwrap(),Ratio64::new(2222222222222,1).unwrap());
|
||||
req(core::f64::consts::PI.try_into().unwrap(),Ratio64::new(884279719003555,281474976710656).unwrap());
|
||||
}
|
||||
|
||||
impl std::ops::Mul<Ratio64> for Ratio64{
|
||||
type Output=Ratio64;
|
||||
#[inline]
|
||||
|
||||
@@ -144,38 +144,10 @@ impl MeshBuilder{
|
||||
}
|
||||
pub fn build(
|
||||
self,
|
||||
mut polygon_groups:Vec<PolygonGroup>,
|
||||
mut graphics_groups:Vec<IndexedGraphicsGroup>,
|
||||
mut physics_groups:Vec<IndexedPhysicsGroup>,
|
||||
polygon_groups:Vec<PolygonGroup>,
|
||||
graphics_groups:Vec<IndexedGraphicsGroup>,
|
||||
physics_groups:Vec<IndexedPhysicsGroup>,
|
||||
)->Mesh{
|
||||
let mut id=0;
|
||||
let mut map=Vec::new();
|
||||
polygon_groups.retain(|group|{
|
||||
let keep=match group{
|
||||
PolygonGroup::PolygonList(polygon_list)=>!polygon_list.0.is_empty(),
|
||||
};
|
||||
if keep{
|
||||
map.push(Some(PolygonGroupId::new(id)));
|
||||
id+=1;
|
||||
}else{
|
||||
map.push(None);
|
||||
}
|
||||
!keep
|
||||
});
|
||||
for group in &mut graphics_groups{
|
||||
// drop empty groups
|
||||
group.groups.retain(|polygon_group_id|map[polygon_group_id.get() as usize].is_some());
|
||||
for polygon_group_id in &mut group.groups{
|
||||
*polygon_group_id=map[polygon_group_id.get() as usize].unwrap();
|
||||
}
|
||||
}
|
||||
for group in &mut physics_groups{
|
||||
// drop empty groups
|
||||
group.groups.retain(|polygon_group_id|map[polygon_group_id.get() as usize].is_some());
|
||||
for polygon_group_id in &mut group.groups{
|
||||
*polygon_group_id=map[polygon_group_id.get() as usize].unwrap();
|
||||
}
|
||||
}
|
||||
let MeshBuilder{
|
||||
unique_pos,
|
||||
unique_normal,
|
||||
|
||||
@@ -53,23 +53,36 @@ impl std::fmt::Display for Error{
|
||||
impl std::error::Error for Error{}
|
||||
|
||||
#[derive(Clone,Copy,Debug)]
|
||||
pub enum RunState{
|
||||
enum RunState{
|
||||
Created,
|
||||
Started{timer:TimerFixed<Realtime<PhysicsTimeInner,TimeInner>,Unpaused>},
|
||||
Finished{timer:TimerFixed<Realtime<PhysicsTimeInner,TimeInner>,Paused>},
|
||||
}
|
||||
impl RunState{
|
||||
|
||||
#[derive(Clone,Copy,Debug)]
|
||||
pub struct Run{
|
||||
state:RunState,
|
||||
flagged:Option<FlagReason>,
|
||||
}
|
||||
|
||||
impl Run{
|
||||
pub fn new()->Self{
|
||||
Self{
|
||||
state:RunState::Created,
|
||||
flagged:None,
|
||||
}
|
||||
}
|
||||
pub fn time(&self,time:PhysicsTime)->Time{
|
||||
match &self{
|
||||
match &self.state{
|
||||
RunState::Created=>Time::ZERO,
|
||||
RunState::Started{timer}=>timer.time(time),
|
||||
RunState::Finished{timer}=>timer.time(),
|
||||
}
|
||||
}
|
||||
pub fn start(&mut self,time:PhysicsTime)->Result<(),Error>{
|
||||
match &self{
|
||||
match &self.state{
|
||||
RunState::Created=>{
|
||||
*self=RunState::Started{
|
||||
self.state=RunState::Started{
|
||||
timer:TimerFixed::new(time,Time::ZERO),
|
||||
};
|
||||
Ok(())
|
||||
@@ -80,10 +93,10 @@ impl RunState{
|
||||
}
|
||||
pub fn finish(&mut self,time:PhysicsTime)->Result<(),Error>{
|
||||
//this uses Copy
|
||||
match &self{
|
||||
match &self.state{
|
||||
RunState::Created=>Err(Error::NotStarted),
|
||||
RunState::Started{timer}=>{
|
||||
*self=RunState::Finished{
|
||||
self.state=RunState::Finished{
|
||||
timer:timer.into_paused(time),
|
||||
};
|
||||
Ok(())
|
||||
@@ -91,39 +104,12 @@ impl RunState{
|
||||
RunState::Finished{..}=>Err(Error::AlreadyFinished),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Copy,Debug)]
|
||||
pub struct Run{
|
||||
state:RunState,
|
||||
flag_reason:Option<FlagReason>,
|
||||
}
|
||||
|
||||
impl Run{
|
||||
pub fn new()->Self{
|
||||
Self{
|
||||
state:RunState::Created,
|
||||
flag_reason:None,
|
||||
}
|
||||
}
|
||||
pub fn time(&self,time:PhysicsTime)->Time{
|
||||
self.state.time(time)
|
||||
}
|
||||
pub fn start(&mut self,time:PhysicsTime)->Result<(),Error>{
|
||||
self.state.start(time)
|
||||
}
|
||||
pub fn finish(&mut self,time:PhysicsTime)->Result<(),Error>{
|
||||
self.state.finish(time)
|
||||
}
|
||||
pub fn flag(&mut self,flag_reason:FlagReason){
|
||||
//don't replace the first reason the run was flagged
|
||||
if self.flag_reason.is_none(){
|
||||
self.flag_reason=Some(flag_reason);
|
||||
if self.flagged.is_none(){
|
||||
self.flagged=Some(flag_reason);
|
||||
}
|
||||
}
|
||||
pub fn flag_reason(&self)->Option<FlagReason>{
|
||||
self.flag_reason
|
||||
}
|
||||
pub fn get_finish_time(&self)->Option<Time>{
|
||||
match &self.state{
|
||||
RunState::Finished{timer}=>Some(timer.time()),
|
||||
|
||||
@@ -69,8 +69,10 @@ impl<In,Out> Scaled<In,Out>
|
||||
const fn get_scale(&self)->Ratio64{
|
||||
self.scale
|
||||
}
|
||||
const fn set_scale(&mut self,new_scale:Ratio64){
|
||||
fn set_scale(&mut self,time:Time<In>,new_scale:Ratio64){
|
||||
let new_time=self.get_time(time);
|
||||
self.scale=new_scale;
|
||||
self.set_time(time,new_time);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +132,7 @@ pub struct TimerFixed<T:TimerState,P:PauseState>{
|
||||
_paused:P,
|
||||
}
|
||||
|
||||
//some scaled timer methods are generic across PauseState
|
||||
//scaled timer methods are generic across PauseState
|
||||
impl<P:PauseState,In,Out> TimerFixed<Scaled<In,Out>,P>
|
||||
where Time<In>:Copy,
|
||||
{
|
||||
@@ -145,22 +147,8 @@ impl<P:PauseState,In,Out> TimerFixed<Scaled<In,Out>,P>
|
||||
pub const fn get_scale(&self)->Ratio64{
|
||||
self.state.get_scale()
|
||||
}
|
||||
}
|
||||
// setting the scale of an unpaused timer is different than a paused timer
|
||||
impl<In,Out> TimerFixed<Scaled<In,Out>,Unpaused>
|
||||
where Time<In>:Copy,
|
||||
{
|
||||
pub fn set_scale(&mut self,time:Time<In>,new_scale:Ratio64){
|
||||
let new_time=self.state.get_time(time);
|
||||
self.state.set_scale(new_scale);
|
||||
self.state.set_time(time,new_time);
|
||||
}
|
||||
}
|
||||
impl<In,Out> TimerFixed<Scaled<In,Out>,Paused>
|
||||
where Time<In>:Copy,
|
||||
{
|
||||
pub fn set_scale(&mut self,new_scale:Ratio64){
|
||||
self.state.set_scale(new_scale);
|
||||
self.state.set_scale(time,new_scale)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,7 +305,7 @@ impl<In,Out> Timer<Scaled<In,Out>>
|
||||
}
|
||||
pub fn set_scale(&mut self,time:Time<In>,new_scale:Ratio64){
|
||||
match self{
|
||||
Self::Paused(timer)=>timer.set_scale(new_scale),
|
||||
Self::Paused(timer)=>timer.set_scale(time,new_scale),
|
||||
Self::Unpaused(timer)=>timer.set_scale(time,new_scale),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ authors = ["Rhys Lloyd <krakow20@gmail.com>"]
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
strafesnet_common.workspace = true
|
||||
strafesnet_common = { version = "0.7.0", path = "../common", registry = "strafesnet" }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "fixed_wide"
|
||||
version = "0.2.2"
|
||||
version = "0.2.1"
|
||||
edition = "2024"
|
||||
repository = "https://git.itzana.me/StrafesNET/strafe-project"
|
||||
license = "MIT OR Apache-2.0"
|
||||
@@ -17,7 +17,7 @@ zeroes=["dep:arrayvec"]
|
||||
bnum = "0.13.0"
|
||||
arrayvec = { version = "0.7.6", optional = true }
|
||||
paste = "1.0.15"
|
||||
ratio_ops = { workspace = true, optional = true }
|
||||
ratio_ops = { version = "0.1.0", path = "../ratio_ops", registry = "strafesnet", optional = true }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -14,12 +14,12 @@ fixed-wide=["dep:fixed_wide","dep:paste"]
|
||||
deferred-division=["dep:ratio_ops"]
|
||||
|
||||
[dependencies]
|
||||
ratio_ops = { workspace = true, optional = true }
|
||||
fixed_wide = { workspace = true, optional = true }
|
||||
ratio_ops = { version = "0.1.0", path = "../ratio_ops", registry = "strafesnet", optional = true }
|
||||
fixed_wide = { version = "0.2.0", path = "../fixed_wide", registry = "strafesnet", optional = true }
|
||||
paste = { version = "1.0.15", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
fixed_wide = { workspace = true, features = ["wide-mul"] }
|
||||
fixed_wide = { path = "../fixed_wide", registry = "strafesnet", features = ["wide-mul"] }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -11,13 +11,13 @@ authors = ["Rhys Lloyd <krakow20@gmail.com>"]
|
||||
|
||||
[dependencies]
|
||||
bytemuck = "1.14.3"
|
||||
glam.workspace = true
|
||||
glam = "0.30.0"
|
||||
regex = { version = "1.11.3", default-features = false, features = ["unicode-perl"] }
|
||||
rbx_mesh = "0.5.0"
|
||||
rbxassetid = { version = "0.1.0", path = "../rbxassetid", registry = "strafesnet" }
|
||||
roblox_emulator = { version = "0.5.1", path = "../roblox_emulator", default-features = false, registry = "strafesnet" }
|
||||
strafesnet_common.workspace = true
|
||||
strafesnet_deferred_loader.workspace = true
|
||||
strafesnet_common = { version = "0.7.0", path = "../common", registry = "strafesnet" }
|
||||
strafesnet_deferred_loader = { version = "0.5.1", path = "../deferred_loader", registry = "strafesnet" }
|
||||
rbx_binary = "2.0.1"
|
||||
rbx_dom_weak = "4.1.0"
|
||||
rbx_reflection = "6.1.0"
|
||||
|
||||
@@ -867,11 +867,6 @@ impl PartialMap1<'_>{
|
||||
deferred_model_deferred_attributes.model.mesh,
|
||||
deferred_model_deferred_attributes.render
|
||||
)?;
|
||||
// If the mesh size is zero we can't auto-scale it, throw it out.
|
||||
if mesh_size.x==integer::Fixed::ZERO||mesh_size.y==integer::Fixed::ZERO||mesh_size.z==integer::Fixed::ZERO{
|
||||
print!("[rbx_loader] Mesh with zero size!");
|
||||
return None;
|
||||
}
|
||||
Some(ModelDeferredAttributes{
|
||||
mesh,
|
||||
deferred_attributes:deferred_model_deferred_attributes.model.deferred_attributes,
|
||||
|
||||
@@ -104,7 +104,7 @@ fn build_mesh2(
|
||||
if let Some(normal_id)=normal_agreement_checker.into_agreed_normal(){
|
||||
polygon_groups_normal_id[normal_id as usize-1].push(face);
|
||||
}else{
|
||||
print!("[union] Empty face!");
|
||||
panic!("Empty face!");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
@@ -158,7 +158,7 @@ fn build_mesh5(
|
||||
if let Some(normal_id)=normal_agreement_checker.into_agreed_normal(){
|
||||
polygon_groups_normal_id[normal_id as usize-1].push(face);
|
||||
}else{
|
||||
print!("[union] Empty face!");
|
||||
panic!("Empty face!");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -12,7 +12,7 @@ default=["run-service"]
|
||||
run-service=[]
|
||||
|
||||
[dependencies]
|
||||
glam.workspace = true
|
||||
glam = "0.30.0"
|
||||
mlua = { version = "0.11.3", features = ["luau"] }
|
||||
phf = { version = "0.13.1", features = ["macros"] }
|
||||
rbx_dom_weak = "4.1.0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "strafesnet_snf"
|
||||
version = "0.3.2"
|
||||
version = "0.3.1"
|
||||
edition = "2024"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
@@ -8,7 +8,7 @@ edition = "2024"
|
||||
[dependencies]
|
||||
binrw = "0.15.0"
|
||||
id = { version = "0.1.0", registry = "strafesnet" }
|
||||
strafesnet_common.workspace = true
|
||||
strafesnet_common = { version = "0.7.0", path = "../common", registry = "strafesnet" }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -18,10 +18,10 @@ rbx_dom_weak = "4.1.0"
|
||||
rbx_reflection_database = "2.0.2"
|
||||
rbx_xml = "2.0.1"
|
||||
rbxassetid = { version = "0.1.0", registry = "strafesnet" }
|
||||
strafesnet_bsp_loader.workspace = true
|
||||
strafesnet_deferred_loader.workspace = true
|
||||
strafesnet_rbx_loader.workspace = true
|
||||
strafesnet_snf.workspace = true
|
||||
strafesnet_bsp_loader = { version = "0.3.1", path = "../lib/bsp_loader", registry = "strafesnet" }
|
||||
strafesnet_deferred_loader = { version = "0.5.1", path = "../lib/deferred_loader", registry = "strafesnet" }
|
||||
strafesnet_rbx_loader = { version = "0.7.0", path = "../lib/rbx_loader", registry = "strafesnet" }
|
||||
strafesnet_snf = { version = "0.3.1", path = "../lib/snf", registry = "strafesnet" }
|
||||
thiserror = "2.0.11"
|
||||
tokio = { version = "1.43.0", features = ["macros", "rt-multi-thread", "fs"] }
|
||||
vbsp = "0.9.1"
|
||||
|
||||
@@ -16,18 +16,18 @@ source = ["dep:strafesnet_deferred_loader", "dep:strafesnet_bsp_loader"]
|
||||
roblox = ["dep:strafesnet_deferred_loader", "dep:strafesnet_rbx_loader"]
|
||||
|
||||
[dependencies]
|
||||
glam.workspace = true
|
||||
glam = "0.30.0"
|
||||
parking_lot = "0.12.1"
|
||||
pollster = "0.4.0"
|
||||
strafesnet_bsp_loader = { workspace = true, optional = true }
|
||||
strafesnet_common.workspace = true
|
||||
strafesnet_deferred_loader = { workspace = true, optional = true }
|
||||
strafesnet_graphics.workspace = true
|
||||
strafesnet_physics.workspace = true
|
||||
strafesnet_rbx_loader = { workspace = true, optional = true }
|
||||
strafesnet_session.workspace = true
|
||||
strafesnet_settings.workspace = true
|
||||
strafesnet_snf = { workspace = true, optional = true }
|
||||
strafesnet_bsp_loader = { path = "../lib/bsp_loader", registry = "strafesnet", optional = true }
|
||||
strafesnet_common = { path = "../lib/common", registry = "strafesnet" }
|
||||
strafesnet_deferred_loader = { path = "../lib/deferred_loader", registry = "strafesnet", optional = true }
|
||||
strafesnet_graphics = { path = "../engine/graphics", registry = "strafesnet" }
|
||||
strafesnet_physics = { path = "../engine/physics", registry = "strafesnet" }
|
||||
strafesnet_rbx_loader = { path = "../lib/rbx_loader", registry = "strafesnet", optional = true }
|
||||
strafesnet_session = { path = "../engine/session", registry = "strafesnet" }
|
||||
strafesnet_settings = { path = "../engine/settings", registry = "strafesnet" }
|
||||
strafesnet_snf = { path = "../lib/snf", registry = "strafesnet", optional = true }
|
||||
wgpu = "28.0.0"
|
||||
winit = "0.30.7"
|
||||
|
||||
|
||||
@@ -37,8 +37,7 @@ pub fn new(
|
||||
config.width=size.width.max(1);
|
||||
config.height=size.height.max(1);
|
||||
surface.configure(&device,&config);
|
||||
let fov=user_settings.calculate_fov(1.0,&glam::uvec2(config.width,config.height)).as_vec2();
|
||||
graphics.resize(&device,&config,fov);
|
||||
graphics.resize(&device,&config,&user_settings);
|
||||
println!("Resize took {:?}",t0.elapsed());
|
||||
}
|
||||
Instruction::Render(frame_state)=>{
|
||||
@@ -57,7 +56,7 @@ pub fn new(
|
||||
..wgpu::TextureViewDescriptor::default()
|
||||
});
|
||||
|
||||
graphics.render(&view,&device,&queue,graphics::view_inv(frame_state.pos(),frame_state.angles()));
|
||||
graphics.render(&view,&device,&queue,frame_state);
|
||||
|
||||
frame.present();
|
||||
}
|
||||
|
||||
@@ -9,5 +9,5 @@ mod graphics_worker;
|
||||
const TITLE:&'static str=concat!("Strafe Client v",env!("CARGO_PKG_VERSION"));
|
||||
|
||||
fn main(){
|
||||
pollster::block_on(setup::setup_and_start(TITLE));
|
||||
setup::setup_and_start(TITLE);
|
||||
}
|
||||
|
||||
@@ -1,38 +1,199 @@
|
||||
use strafesnet_graphics::setup;
|
||||
fn optional_features()->wgpu::Features{
|
||||
wgpu::Features::TEXTURE_COMPRESSION_ASTC
|
||||
|wgpu::Features::TEXTURE_COMPRESSION_ETC2
|
||||
}
|
||||
fn required_features()->wgpu::Features{
|
||||
wgpu::Features::TEXTURE_COMPRESSION_BC
|
||||
}
|
||||
fn required_downlevel_capabilities()->wgpu::DownlevelCapabilities{
|
||||
wgpu::DownlevelCapabilities{
|
||||
flags:wgpu::DownlevelFlags::empty(),
|
||||
shader_model:wgpu::ShaderModel::Sm5,
|
||||
..wgpu::DownlevelCapabilities::default()
|
||||
}
|
||||
}
|
||||
|
||||
struct SetupContextPartial1{
|
||||
backends:wgpu::Backends,
|
||||
instance:wgpu::Instance,
|
||||
}
|
||||
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();
|
||||
attr=attr.with_title(title);
|
||||
event_loop.create_window(attr)
|
||||
}
|
||||
fn create_instance()->SetupContextPartial1{
|
||||
let backends=wgpu::Backends::from_env().unwrap_or_default();
|
||||
SetupContextPartial1{
|
||||
backends,
|
||||
instance:Default::default(),
|
||||
}
|
||||
}
|
||||
impl SetupContextPartial1{
|
||||
fn create_surface<'a>(self,window:&'a winit::window::Window)->Result<SetupContextPartial2<'a>,wgpu::CreateSurfaceError>{
|
||||
Ok(SetupContextPartial2{
|
||||
backends:self.backends,
|
||||
surface:self.instance.create_surface(window)?,
|
||||
instance:self.instance,
|
||||
})
|
||||
}
|
||||
}
|
||||
struct SetupContextPartial2<'a>{
|
||||
backends:wgpu::Backends,
|
||||
instance:wgpu::Instance,
|
||||
surface:wgpu::Surface<'a>,
|
||||
}
|
||||
impl<'a> SetupContextPartial2<'a>{
|
||||
fn pick_adapter(self)->SetupContextPartial3<'a>{
|
||||
let adapter;
|
||||
|
||||
pub async fn setup_and_start(title:&str){
|
||||
//TODO: prefer adapter that implements optional features
|
||||
//let optional_features=optional_features();
|
||||
let required_features=required_features();
|
||||
|
||||
//no helper function smh gotta write it myself
|
||||
let adapters=pollster::block_on(self.instance.enumerate_adapters(self.backends));
|
||||
|
||||
let mut chosen_adapter=None;
|
||||
let mut chosen_adapter_score=0;
|
||||
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{
|
||||
adapter=maybe_chosen_adapter;
|
||||
}else{
|
||||
panic!("No suitable GPU adapters found on the system!");
|
||||
}
|
||||
|
||||
|
||||
let adapter_info=adapter.get_info();
|
||||
println!("Using {} ({:?})", adapter_info.name, adapter_info.backend);
|
||||
|
||||
let required_downlevel_capabilities=required_downlevel_capabilities();
|
||||
let downlevel_capabilities=adapter.get_downlevel_capabilities();
|
||||
assert!(
|
||||
downlevel_capabilities.shader_model >= required_downlevel_capabilities.shader_model,
|
||||
"Adapter does not support the minimum shader model required to run this example: {:?}",
|
||||
required_downlevel_capabilities.shader_model
|
||||
);
|
||||
assert!(
|
||||
downlevel_capabilities
|
||||
.flags
|
||||
.contains(required_downlevel_capabilities.flags),
|
||||
"Adapter does not support the downlevel capabilities required to run this example: {:?}",
|
||||
required_downlevel_capabilities.flags - downlevel_capabilities.flags
|
||||
);
|
||||
SetupContextPartial3{
|
||||
surface:self.surface,
|
||||
adapter,
|
||||
}
|
||||
}
|
||||
}
|
||||
struct SetupContextPartial3<'a>{
|
||||
surface:wgpu::Surface<'a>,
|
||||
adapter:wgpu::Adapter,
|
||||
}
|
||||
impl<'a> SetupContextPartial3<'a>{
|
||||
fn request_device(self)->SetupContextPartial4<'a>{
|
||||
let optional_features=optional_features();
|
||||
let required_features=required_features();
|
||||
|
||||
// Make sure we use the texture resolution limits from the adapter, so we can support images the size of the surface.
|
||||
let needed_limits=strafesnet_graphics::graphics::required_limits().using_resolution(self.adapter.limits());
|
||||
|
||||
let (device, queue)=pollster::block_on(self.adapter
|
||||
.request_device(
|
||||
&wgpu::DeviceDescriptor{
|
||||
label:None,
|
||||
required_features:(optional_features&self.adapter.features())|required_features,
|
||||
required_limits:needed_limits,
|
||||
memory_hints:wgpu::MemoryHints::Performance,
|
||||
trace:wgpu::Trace::Off,
|
||||
experimental_features:wgpu::ExperimentalFeatures::disabled(),
|
||||
},
|
||||
))
|
||||
.expect("Unable to find a suitable GPU adapter!");
|
||||
|
||||
SetupContextPartial4{
|
||||
surface:self.surface,
|
||||
adapter:self.adapter,
|
||||
device,
|
||||
queue,
|
||||
}
|
||||
}
|
||||
}
|
||||
struct SetupContextPartial4<'a>{
|
||||
surface:wgpu::Surface<'a>,
|
||||
adapter:wgpu::Adapter,
|
||||
device:wgpu::Device,
|
||||
queue:wgpu::Queue,
|
||||
}
|
||||
impl<'a> SetupContextPartial4<'a>{
|
||||
fn configure_surface(self,size:&'a winit::dpi::PhysicalSize<u32>)->SetupContext<'a>{
|
||||
let mut config=self.surface
|
||||
.get_default_config(&self.adapter, size.width, size.height)
|
||||
.expect("Surface isn't supported by the adapter.");
|
||||
let surface_view_format=config.format.add_srgb_suffix();
|
||||
config.view_formats.push(surface_view_format);
|
||||
config.present_mode=wgpu::PresentMode::AutoNoVsync;
|
||||
self.surface.configure(&self.device, &config);
|
||||
|
||||
SetupContext{
|
||||
surface:self.surface,
|
||||
device:self.device,
|
||||
queue:self.queue,
|
||||
config,
|
||||
}
|
||||
}
|
||||
}
|
||||
pub struct SetupContext<'a>{
|
||||
pub surface:wgpu::Surface<'a>,
|
||||
pub device:wgpu::Device,
|
||||
pub queue:wgpu::Queue,
|
||||
pub config:wgpu::SurfaceConfiguration,
|
||||
}
|
||||
|
||||
pub fn setup_and_start(title:&str){
|
||||
let event_loop=winit::event_loop::EventLoop::new().unwrap();
|
||||
|
||||
let window=create_window(title,&event_loop).unwrap();
|
||||
|
||||
println!("Initializing the surface...");
|
||||
|
||||
let instance=setup::step1::create_instance();
|
||||
let partial_1=create_instance();
|
||||
|
||||
let surface=setup::step2::create_surface(&instance,&window).unwrap();
|
||||
let window=create_window(title,&event_loop).unwrap();
|
||||
|
||||
let adapter=setup::step3::pick_adapter(&instance,&surface).await.expect("No suitable GPU adapters found on the system!");
|
||||
let partial_2=partial_1.create_surface(&window).unwrap();
|
||||
|
||||
let (device,queue)=setup::step4::request_device(&adapter).await;
|
||||
let partial_3=partial_2.pick_adapter();
|
||||
|
||||
let partial_4=partial_3.request_device();
|
||||
|
||||
let size=window.inner_size();
|
||||
let config=setup::step5::configure_surface(&adapter,&device,&surface,(size.width,size.height));
|
||||
|
||||
let setup_context=partial_4.configure_surface(&size);
|
||||
|
||||
//dedicated thread to ping request redraw back and resize the window doesn't seem logical
|
||||
|
||||
//the thread that spawns the physics thread
|
||||
let mut window_thread=crate::window::worker(
|
||||
&window,
|
||||
device,
|
||||
queue,
|
||||
surface,
|
||||
config,
|
||||
setup_context,
|
||||
);
|
||||
|
||||
for arg in std::env::args().skip(1){
|
||||
|
||||
@@ -239,10 +239,7 @@ impl WindowContext<'_>{
|
||||
}
|
||||
pub fn worker<'a>(
|
||||
window:&'a winit::window::Window,
|
||||
device:wgpu::Device,
|
||||
queue:wgpu::Queue,
|
||||
surface:wgpu::Surface<'a>,
|
||||
config:wgpu::SurfaceConfiguration,
|
||||
setup_context:crate::setup::SetupContext<'a>,
|
||||
)->crate::compat_worker::QNWorker<'a,TimedInstruction<Instruction,SessionTime>>{
|
||||
// WindowContextSetup::new
|
||||
#[cfg(feature="user-install")]
|
||||
@@ -252,13 +249,12 @@ pub fn worker<'a>(
|
||||
|
||||
let user_settings=directories.settings();
|
||||
|
||||
let mut graphics=strafesnet_graphics::graphics::GraphicsState::new(&device,&queue,&config);
|
||||
let mut graphics=strafesnet_graphics::graphics::GraphicsState::new(&setup_context.device,&setup_context.queue,&setup_context.config);
|
||||
graphics.load_user_settings(&user_settings);
|
||||
|
||||
//WindowContextSetup::into_context
|
||||
let screen_size=glam::uvec2(config.width,config.height);
|
||||
let fov=user_settings.calculate_fov(1.0,&screen_size).as_vec2();
|
||||
graphics.resize(&device,&config,fov);
|
||||
let graphics_thread=crate::graphics_worker::new(graphics,config,surface,device,queue);
|
||||
let screen_size=glam::uvec2(setup_context.config.width,setup_context.config.height);
|
||||
let graphics_thread=crate::graphics_worker::new(graphics,setup_context.config,setup_context.surface,setup_context.device,setup_context.queue);
|
||||
let mut window_context=WindowContext{
|
||||
manual_mouse_lock:false,
|
||||
mouse_pos:glam::DVec2::ZERO,
|
||||
|
||||
Reference in New Issue
Block a user