2023-09-01 05:47:55 +00:00
use std ::{ borrow ::Cow , time ::Instant } ;
2023-08-30 01:20:58 +00:00
use wgpu ::{ util ::DeviceExt , AstcBlock , AstcChannel } ;
2023-09-27 09:12:20 +00:00
use model_graphics ::{ GraphicsVertex , ModelGraphicsInstance } ;
2023-10-04 22:58:02 +00:00
use physics ::{ InputInstruction , PhysicsInstruction } ;
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 ;
mod physics ;
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-09-27 09:12:20 +00:00
mod integer ;
2023-08-30 01:20:58 +00:00
struct Entity {
2023-09-06 21:39:44 +00:00
index_count : u32 ,
index_buf : wgpu ::Buffer ,
2023-08-30 01:20:58 +00:00
}
2023-09-08 22:52:51 +00:00
struct ModelGraphics {
2023-09-30 20:00:01 +00:00
instances : Vec < ModelGraphicsInstance > ,
2023-09-06 21:39:44 +00:00
vertex_buf : wgpu ::Buffer ,
entities : Vec < Entity > ,
bind_group : wgpu ::BindGroup ,
model_buf : wgpu ::Buffer ,
2023-09-05 21:58:18 +00:00
}
2023-09-21 05:36:42 +00:00
pub struct GraphicsSamplers {
repeat : wgpu ::Sampler ,
}
pub struct GraphicsBindGroupLayouts {
model : wgpu ::BindGroupLayout ,
}
2023-08-30 01:20:58 +00:00
2023-09-20 22:57:06 +00:00
pub struct GraphicsBindGroups {
camera : wgpu ::BindGroup ,
skybox_texture : wgpu ::BindGroup ,
}
2023-10-04 02:43:41 +00:00
pub struct GraphicsPipelines {
2023-09-20 22:57:06 +00:00
skybox : wgpu ::RenderPipeline ,
model : wgpu ::RenderPipeline ,
}
2023-10-05 03:04:04 +00:00
pub struct GraphicsCamera {
screen_size : glam ::UVec2 ,
fov : glam ::Vec2 , //slope
//camera angles and such are extrapolated and passed in every time
}
#[ inline ]
fn perspective_rh ( fov_x_slope : f32 , fov_y_slope : f32 , z_near : f32 , z_far : f32 ) -> glam ::Mat4 {
//glam_assert!(z_near > 0.0 && z_far > 0.0);
let r = z_far / ( z_near - z_far ) ;
glam ::Mat4 ::from_cols (
glam ::Vec4 ::new ( 1.0 / fov_x_slope , 0.0 , 0.0 , 0.0 ) ,
glam ::Vec4 ::new ( 0.0 , 1.0 / fov_y_slope , 0.0 , 0.0 ) ,
glam ::Vec4 ::new ( 0.0 , 0.0 , r , - 1.0 ) ,
glam ::Vec4 ::new ( 0.0 , 0.0 , r * z_near , 0.0 ) ,
)
}
impl GraphicsCamera {
2023-10-10 02:44:49 +00:00
pub fn new ( screen_size :glam ::UVec2 , fov :glam ::Vec2 ) ->Self {
2023-10-05 03:04:04 +00:00
Self {
screen_size ,
2023-10-10 02:44:49 +00:00
fov ,
2023-10-05 03:04:04 +00:00
}
}
pub fn proj ( & self ) ->glam ::Mat4 {
perspective_rh ( self . fov . x , self . fov . y , 0.5 , 2000.0 )
}
2023-10-06 20:57:39 +00:00
pub fn world ( & self , pos :glam ::Vec3 , angles :glam ::Vec2 ) ->glam ::Mat4 {
2023-10-05 03:04:04 +00:00
//f32 good enough for view matrix
glam ::Mat4 ::from_translation ( pos ) * glam ::Mat4 ::from_euler ( glam ::EulerRot ::YXZ , angles . x , angles . y , 0 f32 )
}
2023-10-06 20:57:39 +00:00
pub fn to_uniform_data ( & self , ( pos , angles ) : ( glam ::Vec3 , glam ::Vec2 ) ) -> [ f32 ; 16 * 4 ] {
2023-10-05 03:04:04 +00:00
let proj = self . proj ( ) ;
let proj_inv = proj . inverse ( ) ;
2023-10-06 20:57:39 +00:00
let view_inv = self . world ( pos , angles ) ;
let view = view_inv . inverse ( ) ;
2023-10-05 03:04:04 +00:00
2023-10-06 20:57:39 +00:00
let mut raw = [ 0 f32 ; 16 * 4 ] ;
2023-10-05 03:04:04 +00:00
raw [ .. 16 ] . copy_from_slice ( & AsRef ::< [ f32 ; 16 ] > ::as_ref ( & proj ) [ .. ] ) ;
raw [ 16 .. 32 ] . copy_from_slice ( & AsRef ::< [ f32 ; 16 ] > ::as_ref ( & proj_inv ) [ .. ] ) ;
2023-10-06 20:57:39 +00:00
raw [ 32 .. 48 ] . copy_from_slice ( & AsRef ::< [ f32 ; 16 ] > ::as_ref ( & view ) [ .. ] ) ;
raw [ 48 .. 64 ] . copy_from_slice ( & AsRef ::< [ f32 ; 16 ] > ::as_ref ( & view_inv ) [ .. ] ) ;
2023-10-05 03:04:04 +00:00
raw
}
}
2023-10-04 02:43:41 +00:00
pub struct GraphicsState {
2023-09-20 22:57:06 +00:00
pipelines : GraphicsPipelines ,
bind_groups : GraphicsBindGroups ,
2023-09-21 05:36:42 +00:00
bind_group_layouts : GraphicsBindGroupLayouts ,
samplers : GraphicsSamplers ,
2023-10-05 03:04:04 +00:00
camera :GraphicsCamera ,
2023-09-06 21:39:44 +00:00
camera_buf : wgpu ::Buffer ,
2023-10-05 03:04:04 +00:00
temp_squid_texture_view : wgpu ::TextureView ,
2023-09-08 22:52:51 +00:00
models : Vec < ModelGraphics > ,
2023-09-06 21:39:44 +00:00
depth_view : wgpu ::TextureView ,
staging_belt : wgpu ::util ::StagingBelt ,
2023-08-30 01:20:58 +00:00
}
2023-10-04 02:43:41 +00:00
impl GraphicsState {
pub fn clear ( & mut self ) {
self . models . clear ( ) ;
}
2023-10-10 02:44:49 +00:00
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 ( ) ;
}
2023-10-04 02:43:41 +00:00
}
pub struct GlobalState {
start_time : std ::time ::Instant ,
manual_mouse_lock :bool ,
2023-10-05 03:04:04 +00:00
mouse :physics ::MouseState ,
2023-10-10 02:44:49 +00:00
user_settings :settings ::UserSettings ,
2023-10-04 02:43:41 +00:00
graphics :GraphicsState ,
2023-10-06 02:45:15 +00:00
physics_thread :worker ::CompatWorker < TimedInstruction < InputInstruction > , physics ::PhysicsOutputState , Box < dyn FnMut ( TimedInstruction < InputInstruction > ) ->physics ::PhysicsOutputState > > ,
2023-10-04 02:43:41 +00:00
}
impl GlobalState {
2023-09-06 21:39:44 +00:00
const DEPTH_FORMAT : wgpu ::TextureFormat = wgpu ::TextureFormat ::Depth24Plus ;
fn create_depth_texture (
config : & wgpu ::SurfaceConfiguration ,
device : & wgpu ::Device ,
) -> wgpu ::TextureView {
let depth_texture = device . create_texture ( & wgpu ::TextureDescriptor {
size : wgpu ::Extent3d {
width : config . width ,
height : config . height ,
depth_or_array_layers : 1 ,
} ,
mip_level_count : 1 ,
sample_count : 1 ,
dimension : wgpu ::TextureDimension ::D2 ,
format : Self ::DEPTH_FORMAT ,
usage : wgpu ::TextureUsages ::RENDER_ATTACHMENT ,
label : None ,
view_formats : & [ ] ,
} ) ;
depth_texture . create_view ( & wgpu ::TextureViewDescriptor ::default ( ) )
}
2023-09-21 05:36:42 +00:00
2023-10-03 23:29:30 +00:00
fn generate_model_graphics ( & mut self , device :& wgpu ::Device , queue :& wgpu ::Queue , indexed_models :model ::IndexedModelInstances ) {
2023-09-23 02:41:27 +00:00
//generate texture view per texture
//idk how to do this gooder lol
let mut double_map = std ::collections ::HashMap ::< u32 , u32 > ::new ( ) ;
2023-10-01 21:56:02 +00:00
let mut texture_loading_threads = Vec ::new ( ) ;
2023-10-01 22:17:10 +00:00
let num_textures = indexed_models . textures . len ( ) ;
for ( i , texture_id ) in indexed_models . textures . into_iter ( ) . enumerate ( ) {
if let Ok ( mut file ) = std ::fs ::File ::open ( std ::path ::Path ::new ( & format! ( " textures/ {} .dds " , texture_id ) ) ) {
2023-10-01 21:56:02 +00:00
double_map . insert ( i as u32 , texture_loading_threads . len ( ) as u32 ) ;
2023-10-01 22:17:10 +00:00
texture_loading_threads . push ( ( texture_id , std ::thread ::spawn ( move | | {
ddsfile ::Dds ::read ( & mut file ) . unwrap ( )
} ) ) ) ;
2023-09-23 02:41:27 +00:00
}
}
2023-10-01 21:56:02 +00:00
2023-10-01 22:17:10 +00:00
let texture_views :Vec < wgpu ::TextureView > = texture_loading_threads . into_iter ( ) . map ( | ( texture_id , thread ) | {
let image = thread . join ( ) . unwrap ( ) ;
2023-10-01 21:56:02 +00:00
let ( mut width , mut height ) = ( image . get_width ( ) , image . get_height ( ) ) ;
let format = match image . header10 . unwrap ( ) . dxgi_format {
ddsfile ::DxgiFormat ::R8G8B8A8_UNorm_sRGB = > wgpu ::TextureFormat ::Rgba8UnormSrgb ,
ddsfile ::DxgiFormat ::BC7_UNorm_sRGB = > {
//floor(w,4), should be ceil(w,4)
width = width / 4 * 4 ;
height = height / 4 * 4 ;
wgpu ::TextureFormat ::Bc7RgbaUnormSrgb
} ,
other = > panic! ( " unsupported format {:?} " , other ) ,
} ;
let size = wgpu ::Extent3d {
width ,
height ,
depth_or_array_layers : 1 ,
} ;
let layer_size = wgpu ::Extent3d {
depth_or_array_layers : 1 ,
.. size
} ;
let max_mips = layer_size . max_mips ( wgpu ::TextureDimension ::D2 ) ;
let texture = device . create_texture_with_data (
queue ,
& wgpu ::TextureDescriptor {
size ,
mip_level_count : max_mips ,
sample_count : 1 ,
dimension : wgpu ::TextureDimension ::D2 ,
format ,
usage : wgpu ::TextureUsages ::TEXTURE_BINDING | wgpu ::TextureUsages ::COPY_DST ,
2023-10-01 22:17:10 +00:00
label : Some ( format! ( " Texture {} " , texture_id ) . as_str ( ) ) ,
2023-10-01 21:56:02 +00:00
view_formats : & [ ] ,
} ,
& image . data ,
) ;
texture . create_view ( & wgpu ::TextureViewDescriptor {
2023-10-01 22:17:10 +00:00
label : Some ( format! ( " Texture {} View " , texture_id ) . as_str ( ) ) ,
2023-10-01 21:56:02 +00:00
dimension : Some ( wgpu ::TextureViewDimension ::D2 ) ,
.. wgpu ::TextureViewDescriptor ::default ( )
} )
} ) . collect ( ) ;
2023-09-29 02:10:22 +00:00
//split groups with different textures into separate models
//the models received here are supposed to be tightly packed, i.e. no code needs to check if two models are using the same groups.
2023-10-01 22:21:19 +00:00
let indexed_models_len = indexed_models . models . len ( ) ;
let mut unique_texture_models = Vec ::with_capacity ( indexed_models_len ) ;
2023-10-04 21:15:53 +00:00
for model in indexed_models . models . into_iter ( ) {
2023-09-30 20:00:01 +00:00
//convert ModelInstance into ModelGraphicsInstance
2023-10-03 23:32:50 +00:00
let instances :Vec < ModelGraphicsInstance > = model . instances . into_iter ( ) . filter_map ( | instance | {
if instance . color . w = = 0.0 {
None
} else {
Some ( ModelGraphicsInstance {
2023-09-27 09:12:20 +00:00
transform : instance . transform . into ( ) ,
normal_transform : Into ::< glam ::Mat3 > ::into ( instance . transform . matrix3 ) . inverse ( ) . transpose ( ) ,
2023-10-03 23:32:50 +00:00
color : instance . color ,
} )
2023-09-30 20:00:01 +00:00
}
} ) . collect ( ) ;
2023-09-29 02:10:22 +00:00
//check each group, if it's using a new texture then make a new clone of the model
let id = unique_texture_models . len ( ) ;
let mut unique_textures = Vec ::new ( ) ;
2023-10-03 23:29:30 +00:00
for group in model . groups . into_iter ( ) {
2023-10-06 21:28:29 +00:00
//ignore zero copy optimization for now
2023-09-29 02:10:22 +00:00
let texture_index = if let Some ( texture_index ) = unique_textures . iter ( ) . position ( | & texture | texture = = group . texture ) {
texture_index
} else {
//create new texture_index
let texture_index = unique_textures . len ( ) ;
unique_textures . push ( group . texture ) ;
2023-09-27 09:12:20 +00:00
unique_texture_models . push ( model_graphics ::IndexedModelGraphicsSingleTexture {
unique_pos :model . unique_pos . iter ( ) . map ( | & v | * Into ::< glam ::Vec3 > ::into ( v ) . as_ref ( ) ) . collect ( ) ,
unique_tex :model . unique_tex . iter ( ) . map ( | v | * v . as_ref ( ) ) . collect ( ) ,
unique_normal :model . unique_normal . iter ( ) . map ( | & v | * Into ::< glam ::Vec3 > ::into ( v ) . as_ref ( ) ) . collect ( ) ,
unique_color :model . unique_color . iter ( ) . map ( | v | * v . as_ref ( ) ) . collect ( ) ,
2023-09-29 02:10:22 +00:00
unique_vertices :model . unique_vertices . clone ( ) ,
texture :group . texture ,
groups :Vec ::new ( ) ,
2023-09-30 20:00:01 +00:00
instances :instances . clone ( ) ,
2023-09-29 02:10:22 +00:00
} ) ;
texture_index
} ;
2023-09-27 09:12:20 +00:00
unique_texture_models [ id + texture_index ] . groups . push ( model_graphics ::IndexedGroupFixedTexture {
2023-09-29 02:10:22 +00:00
polys :group . polys ,
} ) ;
}
}
//de-index models
let mut models = Vec ::with_capacity ( unique_texture_models . len ( ) ) ;
2023-10-02 08:57:15 +00:00
for model in unique_texture_models . into_iter ( ) {
2023-09-29 02:10:22 +00:00
let mut vertices = Vec ::new ( ) ;
let mut index_from_vertex = std ::collections ::HashMap ::new ( ) ; //::<IndexedVertex,usize>
let mut entities = Vec ::new ( ) ;
2023-10-06 22:45:49 +00:00
//this mut be combined in a more complex way if the models use different render patterns per group
2023-09-29 02:10:22 +00:00
let mut indices = Vec ::new ( ) ;
2023-10-06 22:45:49 +00:00
for group in model . groups {
2023-09-29 02:10:22 +00:00
for poly in group . polys {
for end_index in 2 .. poly . vertices . len ( ) {
for & index in & [ 0 , end_index - 1 , end_index ] {
let vertex_index = poly . vertices [ index ] ;
if let Some ( & i ) = index_from_vertex . get ( & vertex_index ) {
indices . push ( i ) ;
} else {
let i = vertices . len ( ) as u16 ;
let vertex = & model . unique_vertices [ vertex_index as usize ] ;
2023-09-27 09:12:20 +00:00
vertices . push ( model_graphics ::GraphicsVertex {
2023-09-29 02:10:22 +00:00
pos : model . unique_pos [ vertex . pos as usize ] ,
tex : model . unique_tex [ vertex . tex as usize ] ,
normal : model . unique_normal [ vertex . normal as usize ] ,
color :model . unique_color [ vertex . color as usize ] ,
} ) ;
index_from_vertex . insert ( vertex_index , i ) ;
indices . push ( i ) ;
}
}
}
}
}
2023-10-06 22:45:49 +00:00
entities . push ( indices ) ;
2023-09-27 09:12:20 +00:00
models . push ( model_graphics ::ModelGraphicsSingleTexture {
2023-09-29 02:10:22 +00:00
instances :model . instances ,
vertices ,
entities ,
texture :model . texture ,
} ) ;
}
2023-10-03 23:29:30 +00:00
//.into_iter() the modeldata vec so entities can be /moved/ to models.entities
2023-09-29 01:44:18 +00:00
let mut model_count = 0 ;
2023-09-22 09:24:31 +00:00
let mut instance_count = 0 ;
2023-10-04 02:43:41 +00:00
let uniform_buffer_binding_size = < GlobalState as framework ::Example > ::required_limits ( ) . max_uniform_buffer_binding_size as usize ;
2023-09-27 00:54:52 +00:00
let chunk_size = uniform_buffer_binding_size / MODEL_BUFFER_SIZE_BYTES ;
2023-10-04 02:43:41 +00:00
self . graphics . models . reserve ( models . len ( ) ) ;
2023-10-02 08:57:15 +00:00
for model in models . into_iter ( ) {
2023-09-29 01:44:18 +00:00
instance_count + = model . instances . len ( ) ;
2023-09-29 02:10:22 +00:00
for instances_chunk in model . instances . rchunks ( chunk_size ) {
2023-09-29 01:44:18 +00:00
model_count + = 1 ;
2023-09-27 00:54:52 +00:00
let model_uniforms = get_instances_buffer_data ( instances_chunk ) ;
2023-09-23 02:41:27 +00:00
let model_buf = device . create_buffer_init ( & wgpu ::util ::BufferInitDescriptor {
2023-09-29 01:44:18 +00:00
label : Some ( format! ( " Model {} Buf " , model_count ) . as_str ( ) ) ,
2023-09-23 02:41:27 +00:00
contents : bytemuck ::cast_slice ( & model_uniforms ) ,
usage : wgpu ::BufferUsages ::UNIFORM | wgpu ::BufferUsages ::COPY_DST ,
} ) ;
2023-09-29 02:10:22 +00:00
let texture_view = match model . texture {
2023-09-23 02:41:27 +00:00
Some ( texture_id ) = > {
match double_map . get ( & texture_id ) {
Some ( & mapped_texture_id ) = > & texture_views [ mapped_texture_id as usize ] ,
2023-10-04 02:43:41 +00:00
None = > & self . graphics . temp_squid_texture_view ,
2023-09-23 02:41:27 +00:00
}
2023-09-21 05:36:42 +00:00
} ,
2023-10-04 02:43:41 +00:00
None = > & self . graphics . temp_squid_texture_view ,
2023-09-23 02:41:27 +00:00
} ;
let model_bind_group = device . create_bind_group ( & wgpu ::BindGroupDescriptor {
2023-10-04 02:43:41 +00:00
layout : & self . graphics . bind_group_layouts . model ,
2023-09-23 02:41:27 +00:00
entries : & [
wgpu ::BindGroupEntry {
binding : 0 ,
resource : model_buf . as_entire_binding ( ) ,
} ,
wgpu ::BindGroupEntry {
binding : 1 ,
resource : wgpu ::BindingResource ::TextureView ( texture_view ) ,
} ,
wgpu ::BindGroupEntry {
binding : 2 ,
2023-10-04 02:43:41 +00:00
resource : wgpu ::BindingResource ::Sampler ( & self . graphics . samplers . repeat ) ,
2023-09-23 02:41:27 +00:00
} ,
] ,
2023-09-29 01:44:18 +00:00
label : Some ( format! ( " Model {} Bind Group " , model_count ) . as_str ( ) ) ,
2023-09-23 02:41:27 +00:00
} ) ;
let vertex_buf = device . create_buffer_init ( & wgpu ::util ::BufferInitDescriptor {
label : Some ( " Vertex " ) ,
2023-09-29 02:10:22 +00:00
contents : bytemuck ::cast_slice ( & model . vertices ) ,
2023-09-23 02:41:27 +00:00
usage : wgpu ::BufferUsages ::VERTEX ,
} ) ;
//all of these are being moved here
2023-10-04 02:43:41 +00:00
self . graphics . models . push ( ModelGraphics {
2023-09-27 00:54:52 +00:00
instances :instances_chunk . to_vec ( ) ,
2023-09-23 02:41:27 +00:00
vertex_buf ,
2023-09-29 02:10:22 +00:00
entities : model . entities . iter ( ) . map ( | indices | {
2023-09-23 02:41:27 +00:00
let index_buf = device . create_buffer_init ( & wgpu ::util ::BufferInitDescriptor {
label : Some ( " Index " ) ,
contents : bytemuck ::cast_slice ( & indices ) ,
usage : wgpu ::BufferUsages ::INDEX ,
} ) ;
Entity {
index_buf ,
index_count : indices . len ( ) as u32 ,
}
} ) . collect ( ) ,
bind_group : model_bind_group ,
model_buf ,
} ) ;
}
2023-09-21 05:36:42 +00:00
}
2023-10-01 22:17:10 +00:00
println! ( " Texture References= {} " , num_textures ) ;
2023-09-29 03:40:49 +00:00
println! ( " Textures Loaded= {} " , texture_views . len ( ) ) ;
println! ( " Indexed Models= {} " , indexed_models_len ) ;
2023-10-04 02:43:41 +00:00
println! ( " Graphics Objects: {} " , self . graphics . models . len ( ) ) ;
2023-09-22 09:24:31 +00:00
println! ( " Graphics Instances: {} " , instance_count ) ;
2023-09-21 05:36:42 +00:00
}
2023-08-30 01:20:58 +00:00
}
2023-10-06 20:57:39 +00:00
const MODEL_BUFFER_SIZE :usize = 4 * 4 + 12 + 4 ; //let size=std::mem::size_of::<ModelInstance>();
2023-09-27 00:54:52 +00:00
const MODEL_BUFFER_SIZE_BYTES :usize = MODEL_BUFFER_SIZE * 4 ;
2023-09-30 20:00:01 +00:00
fn get_instances_buffer_data ( instances :& [ ModelGraphicsInstance ] ) -> Vec < f32 > {
2023-09-26 23:56:19 +00:00
let mut raw = Vec ::with_capacity ( MODEL_BUFFER_SIZE * instances . len ( ) ) ;
2023-09-21 20:02:01 +00:00
for ( i , mi ) in instances . iter ( ) . enumerate ( ) {
2023-09-26 23:56:19 +00:00
let mut v = raw . split_off ( MODEL_BUFFER_SIZE * i ) ;
2023-09-30 20:00:01 +00:00
//model transform
raw . extend_from_slice ( & AsRef ::< [ f32 ; 4 * 4 ] > ::as_ref ( & mi . transform ) [ .. ] ) ;
//normal transform
2023-10-06 20:57:39 +00:00
raw . extend_from_slice ( AsRef ::< [ f32 ; 3 ] > ::as_ref ( & mi . normal_transform . x_axis ) ) ;
raw . extend_from_slice ( & [ 0.0 ] ) ;
raw . extend_from_slice ( AsRef ::< [ f32 ; 3 ] > ::as_ref ( & mi . normal_transform . y_axis ) ) ;
raw . extend_from_slice ( & [ 0.0 ] ) ;
raw . extend_from_slice ( AsRef ::< [ f32 ; 3 ] > ::as_ref ( & mi . normal_transform . z_axis ) ) ;
raw . extend_from_slice ( & [ 0.0 ] ) ;
2023-09-26 23:56:19 +00:00
//color
2023-09-21 20:02:01 +00:00
raw . extend_from_slice ( AsRef ::< [ f32 ; 4 ] > ::as_ref ( & mi . color ) ) ;
2023-09-20 20:03:25 +00:00
raw . append ( & mut v ) ;
}
2023-09-06 21:39:44 +00:00
raw
2023-09-01 21:59:42 +00:00
}
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-09-20 22:57:06 +00:00
let camera_bind_group_layout = device . create_bind_group_layout ( & wgpu ::BindGroupLayoutDescriptor {
2023-09-06 21:39:44 +00:00
label : None ,
entries : & [
wgpu ::BindGroupLayoutEntry {
binding : 0 ,
visibility : wgpu ::ShaderStages ::VERTEX ,
ty : wgpu ::BindingType ::Buffer {
ty : wgpu ::BufferBindingType ::Uniform ,
has_dynamic_offset : false ,
min_binding_size : None ,
} ,
count : None ,
} ,
2023-09-20 22:57:06 +00:00
] ,
} ) ;
let skybox_texture_bind_group_layout = device . create_bind_group_layout ( & wgpu ::BindGroupLayoutDescriptor {
label : Some ( " Skybox Texture Bind Group Layout " ) ,
entries : & [
2023-09-06 21:39:44 +00:00
wgpu ::BindGroupLayoutEntry {
2023-09-20 22:57:06 +00:00
binding : 0 ,
2023-09-06 21:39:44 +00:00
visibility : wgpu ::ShaderStages ::FRAGMENT ,
ty : wgpu ::BindingType ::Texture {
sample_type : wgpu ::TextureSampleType ::Float { filterable : true } ,
multisampled : false ,
view_dimension : wgpu ::TextureViewDimension ::Cube ,
} ,
count : None ,
} ,
wgpu ::BindGroupLayoutEntry {
2023-09-20 22:57:06 +00:00
binding : 1 ,
2023-09-06 21:39:44 +00:00
visibility : wgpu ::ShaderStages ::FRAGMENT ,
ty : wgpu ::BindingType ::Sampler ( wgpu ::SamplerBindingType ::Filtering ) ,
count : None ,
} ,
] ,
} ) ;
let model_bind_group_layout = device . create_bind_group_layout ( & wgpu ::BindGroupLayoutDescriptor {
2023-09-20 22:57:06 +00:00
label : Some ( " Model Bind Group Layout " ) ,
2023-09-06 21:39:44 +00:00
entries : & [
wgpu ::BindGroupLayoutEntry {
binding : 0 ,
visibility : wgpu ::ShaderStages ::VERTEX ,
ty : wgpu ::BindingType ::Buffer {
2023-09-26 02:20:36 +00:00
ty : wgpu ::BufferBindingType ::Uniform ,
2023-09-06 21:39:44 +00:00
has_dynamic_offset : false ,
min_binding_size : None ,
} ,
count : None ,
} ,
2023-09-20 22:57:06 +00:00
wgpu ::BindGroupLayoutEntry {
binding : 1 ,
visibility : wgpu ::ShaderStages ::FRAGMENT ,
ty : wgpu ::BindingType ::Texture {
sample_type : wgpu ::TextureSampleType ::Float { filterable : true } ,
multisampled : false ,
view_dimension : wgpu ::TextureViewDimension ::D2 ,
} ,
count : None ,
} ,
wgpu ::BindGroupLayoutEntry {
binding : 2 ,
visibility : wgpu ::ShaderStages ::FRAGMENT ,
ty : wgpu ::BindingType ::Sampler ( wgpu ::SamplerBindingType ::Filtering ) ,
count : None ,
} ,
2023-09-06 21:39:44 +00:00
] ,
} ) ;
2023-09-20 22:57:06 +00:00
let clamp_sampler = device . create_sampler ( & wgpu ::SamplerDescriptor {
label : Some ( " Clamp Sampler " ) ,
address_mode_u : wgpu ::AddressMode ::ClampToEdge ,
address_mode_v : wgpu ::AddressMode ::ClampToEdge ,
address_mode_w : wgpu ::AddressMode ::ClampToEdge ,
mag_filter : wgpu ::FilterMode ::Linear ,
min_filter : wgpu ::FilterMode ::Linear ,
mipmap_filter : wgpu ::FilterMode ::Linear ,
.. Default ::default ( )
} ) ;
let repeat_sampler = device . create_sampler ( & wgpu ::SamplerDescriptor {
label : Some ( " Repeat Sampler " ) ,
address_mode_u : wgpu ::AddressMode ::Repeat ,
address_mode_v : wgpu ::AddressMode ::Repeat ,
address_mode_w : wgpu ::AddressMode ::Repeat ,
mag_filter : wgpu ::FilterMode ::Linear ,
min_filter : wgpu ::FilterMode ::Linear ,
mipmap_filter : wgpu ::FilterMode ::Linear ,
.. Default ::default ( )
} ) ;
2023-09-06 21:39:44 +00:00
// Create the render pipeline
let shader = device . create_shader_module ( wgpu ::ShaderModuleDescriptor {
label : None ,
source : wgpu ::ShaderSource ::Wgsl ( Cow ::Borrowed ( include_str! ( " shader.wgsl " ) ) ) ,
} ) ;
2023-09-21 00:01:57 +00:00
//load textures
2023-09-20 23:58:56 +00:00
let device_features = device . features ( ) ;
2023-09-21 00:01:06 +00:00
let skybox_texture_view = {
let skybox_format = if device_features . contains ( wgpu ::Features ::TEXTURE_COMPRESSION_ASTC ) {
log ::info! ( " Using ASTC " ) ;
wgpu ::TextureFormat ::Astc {
block : AstcBlock ::B4x4 ,
channel : AstcChannel ::UnormSrgb ,
}
} else if device_features . contains ( wgpu ::Features ::TEXTURE_COMPRESSION_ETC2 ) {
log ::info! ( " Using ETC2 " ) ;
wgpu ::TextureFormat ::Etc2Rgb8UnormSrgb
} else if device_features . contains ( wgpu ::Features ::TEXTURE_COMPRESSION_BC ) {
log ::info! ( " Using BC " ) ;
wgpu ::TextureFormat ::Bc1RgbaUnormSrgb
} else {
log ::info! ( " Using plain " ) ;
wgpu ::TextureFormat ::Bgra8UnormSrgb
} ;
2023-09-20 23:58:56 +00:00
2023-09-22 22:20:41 +00:00
let bytes = match skybox_format {
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 " ) [ .. ] ,
_ = > unreachable! ( ) ,
} ;
let skybox_image = ddsfile ::Dds ::read ( & mut std ::io ::Cursor ::new ( bytes ) ) . unwrap ( ) ;
2023-09-21 00:01:06 +00:00
let size = wgpu ::Extent3d {
2023-09-22 22:20:41 +00:00
width : skybox_image . get_width ( ) ,
height : skybox_image . get_height ( ) ,
2023-09-21 00:01:06 +00:00
depth_or_array_layers : 6 ,
} ;
2023-09-20 23:58:56 +00:00
2023-09-21 00:01:06 +00:00
let layer_size = wgpu ::Extent3d {
depth_or_array_layers : 1 ,
.. size
} ;
let max_mips = layer_size . max_mips ( wgpu ::TextureDimension ::D2 ) ;
2023-09-20 23:58:56 +00:00
2023-09-21 00:01:06 +00:00
log ::debug! (
" Copying {:?} skybox images of size {}, {}, 6 with {} mips to gpu " ,
skybox_format ,
2023-09-22 22:20:41 +00:00
size . width ,
size . height ,
2023-09-21 00:01:06 +00:00
max_mips ,
) ;
let skybox_texture = device . create_texture_with_data (
queue ,
& wgpu ::TextureDescriptor {
size ,
mip_level_count : max_mips ,
sample_count : 1 ,
dimension : wgpu ::TextureDimension ::D2 ,
format : skybox_format ,
usage : wgpu ::TextureUsages ::TEXTURE_BINDING | wgpu ::TextureUsages ::COPY_DST ,
label : Some ( " Skybox Texture " ) ,
view_formats : & [ ] ,
} ,
& skybox_image . data ,
) ;
skybox_texture . create_view ( & wgpu ::TextureViewDescriptor {
label : Some ( " Skybox Texture View " ) ,
dimension : Some ( wgpu ::TextureViewDimension ::Cube ) ,
.. wgpu ::TextureViewDescriptor ::default ( )
} )
} ;
2023-09-06 21:39:44 +00:00
2023-09-21 00:01:57 +00:00
//squid
let squid_texture_view = {
2023-09-22 03:56:24 +00:00
let bytes = include_bytes! ( " ../images/squid.dds " ) ;
2023-09-21 18:56:03 +00:00
2023-09-22 03:56:24 +00:00
let image = ddsfile ::Dds ::read ( & mut std ::io ::Cursor ::new ( bytes ) ) . unwrap ( ) ;
2023-09-21 18:56:03 +00:00
2023-09-21 00:01:57 +00:00
let size = wgpu ::Extent3d {
2023-09-21 18:56:03 +00:00
width : image . get_width ( ) ,
height : image . get_height ( ) ,
2023-09-21 00:01:57 +00:00
depth_or_array_layers : 1 ,
} ;
let layer_size = wgpu ::Extent3d {
depth_or_array_layers : 1 ,
.. size
} ;
let max_mips = layer_size . max_mips ( wgpu ::TextureDimension ::D2 ) ;
let texture = device . create_texture_with_data (
queue ,
& wgpu ::TextureDescriptor {
size ,
mip_level_count : max_mips ,
sample_count : 1 ,
dimension : wgpu ::TextureDimension ::D2 ,
format : wgpu ::TextureFormat ::Bc7RgbaUnorm ,
usage : wgpu ::TextureUsages ::TEXTURE_BINDING | wgpu ::TextureUsages ::COPY_DST ,
label : Some ( " Squid Texture " ) ,
view_formats : & [ ] ,
} ,
& image . data ,
) ;
texture . create_view ( & wgpu ::TextureViewDescriptor {
label : Some ( " Squid Texture View " ) ,
dimension : Some ( wgpu ::TextureViewDimension ::D2 ) ,
.. wgpu ::TextureViewDescriptor ::default ( )
} )
} ;
2023-09-29 01:28:10 +00:00
let model_pipeline_layout = device . create_pipeline_layout ( & wgpu ::PipelineLayoutDescriptor {
2023-09-06 21:39:44 +00:00
label : None ,
2023-09-20 22:57:06 +00:00
bind_group_layouts : & [
& camera_bind_group_layout ,
2023-09-29 01:28:10 +00:00
& skybox_texture_bind_group_layout ,
2023-09-20 22:57:06 +00:00
& model_bind_group_layout ,
2023-09-29 01:28:10 +00:00
] ,
push_constant_ranges : & [ ] ,
} ) ;
let sky_pipeline_layout = device . create_pipeline_layout ( & wgpu ::PipelineLayoutDescriptor {
label : None ,
bind_group_layouts : & [
& camera_bind_group_layout ,
2023-09-20 22:57:06 +00:00
& skybox_texture_bind_group_layout ,
] ,
2023-09-06 21:39:44 +00:00
push_constant_ranges : & [ ] ,
} ) ;
// Create the render pipelines
let sky_pipeline = device . create_render_pipeline ( & wgpu ::RenderPipelineDescriptor {
2023-09-20 22:57:06 +00:00
label : Some ( " Sky Pipeline " ) ,
2023-09-29 01:28:10 +00:00
layout : Some ( & sky_pipeline_layout ) ,
2023-09-06 21:39:44 +00:00
vertex : wgpu ::VertexState {
module : & shader ,
entry_point : " vs_sky " ,
buffers : & [ ] ,
} ,
fragment : Some ( wgpu ::FragmentState {
module : & shader ,
entry_point : " fs_sky " ,
targets : & [ Some ( config . view_formats [ 0 ] . into ( ) ) ] ,
} ) ,
primitive : wgpu ::PrimitiveState {
front_face : wgpu ::FrontFace ::Cw ,
.. Default ::default ( )
} ,
depth_stencil : Some ( wgpu ::DepthStencilState {
format : Self ::DEPTH_FORMAT ,
depth_write_enabled : false ,
depth_compare : wgpu ::CompareFunction ::LessEqual ,
stencil : wgpu ::StencilState ::default ( ) ,
bias : wgpu ::DepthBiasState ::default ( ) ,
} ) ,
multisample : wgpu ::MultisampleState ::default ( ) ,
multiview : None ,
} ) ;
2023-09-20 22:57:06 +00:00
let model_pipeline = device . create_render_pipeline ( & wgpu ::RenderPipelineDescriptor {
label : Some ( " Model Pipeline " ) ,
2023-09-29 01:28:10 +00:00
layout : Some ( & model_pipeline_layout ) ,
2023-09-06 21:39:44 +00:00
vertex : wgpu ::VertexState {
module : & shader ,
2023-09-20 22:57:06 +00:00
entry_point : " vs_entity_texture " ,
2023-09-06 21:39:44 +00:00
buffers : & [ wgpu ::VertexBufferLayout {
2023-09-27 09:12:20 +00:00
array_stride : std ::mem ::size_of ::< GraphicsVertex > ( ) as wgpu ::BufferAddress ,
2023-09-06 21:39:44 +00:00
step_mode : wgpu ::VertexStepMode ::Vertex ,
2023-09-21 20:02:01 +00:00
attributes : & wgpu ::vertex_attr_array! [ 0 = > Float32x3 , 1 = > Float32x2 , 2 = > Float32x3 , 3 = > Float32x4 ] ,
2023-09-06 21:39:44 +00:00
} ] ,
} ,
fragment : Some ( wgpu ::FragmentState {
module : & shader ,
2023-09-20 22:57:06 +00:00
entry_point : " fs_entity_texture " ,
2023-09-06 21:39:44 +00:00
targets : & [ Some ( config . view_formats [ 0 ] . into ( ) ) ] ,
} ) ,
primitive : wgpu ::PrimitiveState {
front_face : wgpu ::FrontFace ::Cw ,
.. Default ::default ( )
} ,
depth_stencil : Some ( wgpu ::DepthStencilState {
format : Self ::DEPTH_FORMAT ,
depth_write_enabled : true ,
depth_compare : wgpu ::CompareFunction ::LessEqual ,
stencil : wgpu ::StencilState ::default ( ) ,
bias : wgpu ::DepthBiasState ::default ( ) ,
} ) ,
multisample : wgpu ::MultisampleState ::default ( ) ,
multiview : None ,
} ) ;
2023-10-05 03:04:04 +00:00
let mut physics = physics ::PhysicsState ::default ( ) ;
2023-10-10 02:44:49 +00:00
physics . load_user_settings ( & user_settings ) ;
let screen_size = glam ::uvec2 ( config . width , config . height ) ;
let camera = GraphicsCamera ::new ( screen_size , user_settings . calculate_fov ( 1.0 , & screen_size ) . as_vec2 ( ) ) ;
2023-10-05 03:04:04 +00:00
let camera_uniforms = camera . to_uniform_data ( physics . output ( ) . adjust_mouse ( & physics . next_mouse ) ) ;
2023-09-20 23:58:56 +00:00
let camera_buf = device . create_buffer_init ( & wgpu ::util ::BufferInitDescriptor {
label : Some ( " Camera " ) ,
contents : bytemuck ::cast_slice ( & camera_uniforms ) ,
usage : wgpu ::BufferUsages ::UNIFORM | wgpu ::BufferUsages ::COPY_DST ,
2023-09-06 21:39:44 +00:00
} ) ;
2023-09-20 22:57:06 +00:00
let camera_bind_group = device . create_bind_group ( & wgpu ::BindGroupDescriptor {
layout : & camera_bind_group_layout ,
2023-09-06 21:39:44 +00:00
entries : & [
wgpu ::BindGroupEntry {
binding : 0 ,
resource : camera_buf . as_entire_binding ( ) ,
} ,
2023-09-20 22:57:06 +00:00
] ,
label : Some ( " Camera " ) ,
} ) ;
2023-10-05 03:04:04 +00:00
2023-09-20 22:57:06 +00:00
let skybox_texture_bind_group = device . create_bind_group ( & wgpu ::BindGroupDescriptor {
layout : & skybox_texture_bind_group_layout ,
entries : & [
2023-09-06 21:39:44 +00:00
wgpu ::BindGroupEntry {
2023-09-20 22:57:06 +00:00
binding : 0 ,
resource : wgpu ::BindingResource ::TextureView ( & skybox_texture_view ) ,
2023-09-06 21:39:44 +00:00
} ,
wgpu ::BindGroupEntry {
2023-09-20 22:57:06 +00:00
binding : 1 ,
resource : wgpu ::BindingResource ::Sampler ( & clamp_sampler ) ,
2023-09-06 21:39:44 +00:00
} ,
] ,
2023-09-20 22:57:06 +00:00
label : Some ( " Sky Texture " ) ,
2023-09-06 21:39:44 +00:00
} ) ;
let depth_view = Self ::create_depth_texture ( config , device ) ;
2023-10-10 02:44:49 +00:00
let mut graphics = GraphicsState {
2023-09-20 22:57:06 +00:00
pipelines :GraphicsPipelines {
skybox :sky_pipeline ,
model :model_pipeline
} ,
bind_groups :GraphicsBindGroups {
camera :camera_bind_group ,
skybox_texture :skybox_texture_bind_group ,
} ,
2023-10-05 03:04:04 +00:00
camera ,
2023-09-06 21:39:44 +00:00
camera_buf ,
2023-09-21 05:36:42 +00:00
models : Vec ::new ( ) ,
2023-09-06 21:39:44 +00:00
depth_view ,
staging_belt : wgpu ::util ::StagingBelt ::new ( 0x100 ) ,
2023-09-21 05:36:42 +00:00
bind_group_layouts : GraphicsBindGroupLayouts { model : model_bind_group_layout } ,
samplers : GraphicsSamplers { repeat : repeat_sampler } ,
temp_squid_texture_view : squid_texture_view ,
} ;
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-04 02:43:41 +00:00
state . load_file ( std ::path ::PathBuf ::from ( & args [ 1 ] ) , device , queue ) ;
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
fn load_file ( & mut self , path : std ::path ::PathBuf , device : & wgpu ::Device , queue : & wgpu ::Queue ) {
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 ) ) {
2023-10-02 22:27:41 +00:00
if let Some ( indexed_model_instances ) = {
2023-10-02 00:18:29 +00:00
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 ) ) ,
} {
2023-10-02 22:27:41 +00:00
Ok ( dom ) = > Some ( load_roblox ::generate_indexed_models ( dom ) ) ,
2023-10-02 00:18:29 +00:00
Err ( e ) = > {
println! ( " Error loading roblox file: {:?} " , e ) ;
None
2023-09-30 09:53:25 +00:00
} ,
2023-09-26 21:25:44 +00:00
}
2023-10-02 00:18:29 +00:00
} ,
2023-10-02 22:27:41 +00:00
//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
} ,
2023-09-26 21:25:44 +00:00
}
2023-10-02 00:18:29 +00:00
} {
2023-10-02 22:27:41 +00:00
let spawn_point = indexed_model_instances . spawn_point ;
2023-10-02 00:18:29 +00:00
//if generate_indexed_models succeeds, clear the previous ones
2023-10-04 02:43:41 +00:00
self . graphics . clear ( ) ;
2023-10-05 03:04:04 +00:00
let mut physics = physics ::PhysicsState ::default ( ) ;
physics . game . stage_id = 0 ;
physics . spawn_point = spawn_point ;
physics . process_instruction ( instruction ::TimedInstruction {
time :physics . time ,
instruction : PhysicsInstruction ::Input ( physics ::PhysicsInputInstruction ::Reset ) ,
} ) ;
2023-10-10 02:44:49 +00:00
physics . load_user_settings ( & self . user_settings ) ;
2023-10-05 03:04:04 +00:00
physics . generate_models ( & indexed_model_instances ) ;
self . physics_thread = physics . into_worker ( ) ;
2023-10-10 02:44:49 +00:00
//graphics.load_user_settings(&self.user_settings);
2023-10-02 00:18:29 +00:00
self . generate_model_graphics ( device , queue , indexed_model_instances ) ;
//manual reset
2023-09-21 05:36:42 +00:00
} else {
2023-10-02 00:18:29 +00:00
println! ( " No modeldatas were generated " ) ;
2023-09-21 05:36:42 +00:00
}
2023-10-02 00:18:29 +00:00
} else {
println! ( " Failed to read first 8 bytes and seek back to beginning of file. " ) ;
}
} else {
println! ( " Could not open file " ) ;
}
}
#[ 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 {
winit ::event ::WindowEvent ::DroppedFile ( path ) = > self . load_file ( path , device , queue ) ,
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
}
}
fn resize (
& mut self ,
config : & wgpu ::SurfaceConfiguration ,
device : & wgpu ::Device ,
_queue : & wgpu ::Queue ,
) {
2023-10-04 02:43:41 +00:00
self . graphics . depth_view = Self ::create_depth_texture ( config , device ) ;
2023-10-10 02:44:49 +00:00
self . graphics . camera . screen_size = glam ::uvec2 ( config . width , config . height ) ;
self . graphics . load_user_settings ( & self . user_settings ) ;
2023-09-06 21:39:44 +00:00
}
fn render (
& mut self ,
view : & wgpu ::TextureView ,
device : & wgpu ::Device ,
queue : & wgpu ::Queue ,
2023-09-22 22:19:44 +00:00
_spawner : & framework ::Spawner ,
2023-09-06 21:39:44 +00:00
) {
2023-10-05 03:04:04 +00:00
//ideally this would be scheduled to execute and finish right before the render.
2023-09-27 09:12:20 +00:00
let time = integer ::Time ::from_nanos ( self . start_time . elapsed ( ) . as_nanos ( ) as i64 ) ;
2023-10-05 03:04:04 +00:00
self . physics_thread . send ( TimedInstruction {
time ,
instruction :InputInstruction ::Idle ,
} ) . unwrap ( ) ;
//update time lol
self . mouse . time = time ;
2023-09-19 06:57:42 +00:00
2023-09-06 21:39:44 +00:00
let mut encoder =
device . create_command_encoder ( & wgpu ::CommandEncoderDescriptor { label : None } ) ;
// update rotation
2023-10-05 03:04:04 +00:00
let camera_uniforms = self . graphics . camera . to_uniform_data ( self . physics_thread . grab_clone ( ) . adjust_mouse ( & self . mouse ) ) ;
2023-10-04 02:43:41 +00:00
self . graphics . staging_belt
2023-09-06 21:39:44 +00:00
. write_buffer (
& mut encoder ,
2023-10-04 02:43:41 +00:00
& self . graphics . camera_buf ,
2023-09-06 21:39:44 +00:00
0 ,
wgpu ::BufferSize ::new ( ( camera_uniforms . len ( ) * 4 ) as wgpu ::BufferAddress ) . unwrap ( ) ,
device ,
)
. copy_from_slice ( bytemuck ::cast_slice ( & camera_uniforms ) ) ;
//This code only needs to run when the uniforms change
2023-10-05 05:21:05 +00:00
/*
2023-10-04 02:43:41 +00:00
for model in self . graphics . models . iter ( ) {
2023-09-21 20:02:01 +00:00
let model_uniforms = get_instances_buffer_data ( & model . instances ) ;
2023-10-04 02:43:41 +00:00
self . graphics . staging_belt
2023-09-06 21:39:44 +00:00
. write_buffer (
& mut encoder ,
& model . model_buf , //description of where data will be written when command is executed
0 , //offset in staging belt?
wgpu ::BufferSize ::new ( ( model_uniforms . len ( ) * 4 ) as wgpu ::BufferAddress ) . unwrap ( ) ,
device ,
)
. copy_from_slice ( bytemuck ::cast_slice ( & model_uniforms ) ) ;
}
2023-10-05 05:21:05 +00:00
* /
2023-10-04 02:43:41 +00:00
self . graphics . staging_belt . finish ( ) ;
2023-09-06 21:39:44 +00:00
{
let mut rpass = encoder . begin_render_pass ( & wgpu ::RenderPassDescriptor {
label : None ,
color_attachments : & [ Some ( wgpu ::RenderPassColorAttachment {
view ,
resolve_target : None ,
ops : wgpu ::Operations {
load : wgpu ::LoadOp ::Clear ( wgpu ::Color {
r : 0.1 ,
g : 0.2 ,
b : 0.3 ,
a : 1.0 ,
} ) ,
store : true ,
} ,
} ) ] ,
depth_stencil_attachment : Some ( wgpu ::RenderPassDepthStencilAttachment {
2023-10-04 02:43:41 +00:00
view : & self . graphics . depth_view ,
2023-09-06 21:39:44 +00:00
depth_ops : Some ( wgpu ::Operations {
load : wgpu ::LoadOp ::Clear ( 1.0 ) ,
store : false ,
} ) ,
stencil_ops : None ,
} ) ,
} ) ;
2023-10-04 02:43:41 +00:00
rpass . set_bind_group ( 0 , & self . graphics . bind_groups . camera , & [ ] ) ;
rpass . set_bind_group ( 1 , & self . graphics . bind_groups . skybox_texture , & [ ] ) ;
2023-09-06 21:39:44 +00:00
2023-10-04 02:43:41 +00:00
rpass . set_pipeline ( & self . graphics . pipelines . model ) ;
for model in self . graphics . models . iter ( ) {
2023-09-29 01:28:10 +00:00
rpass . set_bind_group ( 2 , & model . bind_group , & [ ] ) ;
2023-09-06 21:39:44 +00:00
rpass . set_vertex_buffer ( 0 , model . vertex_buf . slice ( .. ) ) ;
for entity in model . entities . iter ( ) {
rpass . set_index_buffer ( entity . index_buf . slice ( .. ) , wgpu ::IndexFormat ::Uint16 ) ;
2023-09-21 20:02:01 +00:00
rpass . draw_indexed ( 0 .. entity . index_count , 0 , 0 .. model . instances . len ( ) as u32 ) ;
2023-09-06 21:39:44 +00:00
}
}
2023-10-04 02:43:41 +00:00
rpass . set_pipeline ( & self . graphics . pipelines . skybox ) ;
2023-09-06 21:39:44 +00:00
rpass . draw ( 0 .. 3 , 0 .. 1 ) ;
}
queue . submit ( std ::iter ::once ( encoder . finish ( ) ) ) ;
2023-10-04 02:43:41 +00:00
self . graphics . staging_belt . recall ( ) ;
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
}