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-30 20:00:01 +00:00
use model ::{ Vertex , ModelInstance , ModelGraphicsInstance } ;
2023-09-20 00:53:29 +00:00
use body ::{ InputInstruction , PhysicsInstruction } ;
use instruction ::{ TimedInstruction , InstructionConsumer } ;
2023-08-30 01:20:58 +00:00
2023-09-22 22:19:44 +00:00
mod body ;
2023-09-22 22:21:13 +00:00
mod model ;
2023-09-22 22:19:44 +00:00
mod zeroes ;
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-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-04 02:43:41 +00:00
pub struct GraphicsState {
2023-09-20 00:53:29 +00:00
screen_size : ( u32 , u32 ) ,
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 ,
temp_squid_texture_view : wgpu ::TextureView ,
2023-09-06 21:39:44 +00:00
camera_buf : wgpu ::Buffer ,
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 ( ) ;
}
}
pub struct GlobalState {
start_time : std ::time ::Instant ,
manual_mouse_lock :bool ,
graphics :GraphicsState ,
physics :body ::PhysicsState ,
}
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-09-28 23:15:12 +00:00
fn generate_model_physics ( & mut self , indexed_models :& model ::IndexedModelInstances ) {
2023-10-04 02:46:54 +00:00
let mut starts = Vec ::new ( ) ;
let mut spawns = Vec ::new ( ) ;
let mut ordered_checkpoints = Vec ::new ( ) ;
let mut unordered_checkpoints = Vec ::new ( ) ;
2023-09-28 23:15:12 +00:00
for model in & indexed_models . models {
2023-09-21 21:11:41 +00:00
//make aabb and run vertices to get realistic bounds
2023-09-28 23:15:12 +00:00
for model_instance in & model . instances {
2023-10-03 23:34:54 +00:00
if let Some ( model_physics ) = body ::ModelPhysics ::from_model ( model , model_instance ) {
2023-10-04 02:46:54 +00:00
let model_id = self . physics . models . len ( ) as u32 ;
//snoop it before it gets stolen
for attr in model_instance . temp_indexing . iter ( ) {
match attr {
model ::TempIndexedAttributes ::Start { mode_id } = > starts . push ( ( * mode_id , model_id ) ) ,
model ::TempIndexedAttributes ::Spawn { mode_id , stage_id } = > spawns . push ( ( * mode_id , model_id , * stage_id ) ) ,
model ::TempIndexedAttributes ::OrderedCheckpoint { mode_id , checkpoint_id } = > ordered_checkpoints . push ( ( * mode_id , model_id , * checkpoint_id ) ) ,
model ::TempIndexedAttributes ::UnorderedCheckpoint { mode_id } = > unordered_checkpoints . push ( ( * mode_id , model_id ) ) ,
}
}
//steal it
2023-10-03 23:34:54 +00:00
self . physics . models . push ( model_physics ) ;
}
2023-09-28 23:15:12 +00:00
}
}
2023-10-04 02:46:54 +00:00
//I don't wanna write structs for temporary structures
//this code builds ModeDescriptions from the unsorted lists at the top of the function
starts . sort_by_key ( | tup | tup . 0 ) ;
let mut eshmep = std ::collections ::HashMap ::new ( ) ;
let mut modedatas :Vec < ( u32 , Vec < ( u32 , u32 ) > , Vec < ( u32 , u32 ) > , Vec < u32 > ) > = starts . into_iter ( ) . enumerate ( ) . map ( | ( i , tup ) | {
eshmep . insert ( tup . 0 , i ) ;
( tup . 1 , Vec ::new ( ) , Vec ::new ( ) , Vec ::new ( ) )
} ) . collect ( ) ;
for tup in spawns {
if let Some ( mode_id ) = eshmep . get ( & tup . 0 ) {
if let Some ( modedata ) = modedatas . get_mut ( * mode_id ) {
modedata . 1. push ( ( tup . 2 , tup . 1 ) ) ;
}
}
}
for tup in ordered_checkpoints {
if let Some ( mode_id ) = eshmep . get ( & tup . 0 ) {
if let Some ( modedata ) = modedatas . get_mut ( * mode_id ) {
modedata . 2. push ( ( tup . 2 , tup . 1 ) ) ;
}
}
}
for tup in unordered_checkpoints {
if let Some ( mode_id ) = eshmep . get ( & tup . 0 ) {
if let Some ( modedata ) = modedatas . get_mut ( * mode_id ) {
modedata . 3. push ( tup . 1 ) ;
}
}
}
2023-10-04 21:13:25 +00:00
let num_modes = self . physics . modes . len ( ) ;
for ( mode_id , mode ) in eshmep {
self . physics . mode_from_mode_id . insert ( mode_id , num_modes + mode ) ;
}
2023-10-04 02:46:54 +00:00
self . physics . modes . append ( & mut modedatas . into_iter ( ) . map ( | mut tup | {
tup . 1. sort_by_key ( | tup | tup . 0 ) ;
tup . 2. sort_by_key ( | tup | tup . 0 ) ;
2023-10-04 21:13:25 +00:00
let mut eshmep1 = std ::collections ::HashMap ::new ( ) ;
let mut eshmep2 = std ::collections ::HashMap ::new ( ) ;
2023-10-04 02:46:54 +00:00
model ::ModeDescription {
start :tup . 0 ,
2023-10-04 21:13:25 +00:00
spawns :tup . 1. into_iter ( ) . enumerate ( ) . map ( | ( i , tup ) | { eshmep1 . insert ( tup . 0 , i ) ; tup . 1 } ) . collect ( ) ,
ordered_checkpoints :tup . 2. into_iter ( ) . enumerate ( ) . map ( | ( i , tup ) | { eshmep2 . insert ( tup . 0 , i ) ; tup . 1 } ) . collect ( ) ,
2023-10-04 02:46:54 +00:00
unordered_checkpoints :tup . 3 ,
2023-10-04 21:13:25 +00:00
spawn_from_stage_id :eshmep1 ,
ordered_checkpoint_from_checkpoint_id :eshmep2 ,
2023-10-04 02:46:54 +00:00
}
} ) . collect ( ) ) ;
2023-09-22 09:24:31 +00:00
println! ( " Physics Objects: {} " , self . physics . models . len ( ) ) ;
2023-09-21 21:11:41 +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-02 08:57:15 +00:00
for mut 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 {
transform : glam ::Mat4 ::from ( instance . transform ) ,
normal_transform : glam ::Mat4 ::from ( instance . transform . inverse ( ) ) . transpose ( ) ,
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-09-29 02:10:22 +00:00
//ignore zero coppy optimization for now
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 ) ;
unique_texture_models . push ( model ::IndexedModelSingleTexture {
unique_pos :model . unique_pos . clone ( ) ,
unique_tex :model . unique_tex . clone ( ) ,
unique_normal :model . unique_normal . clone ( ) ,
unique_color :model . unique_color . clone ( ) ,
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
} ;
unique_texture_models [ id + texture_index ] . groups . push ( model ::IndexedGroupFixedTexture {
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-09-30 23:18:23 +00:00
//TODO: combine groups using the same render pattern
2023-09-29 02:10:22 +00:00
for group in model . groups {
let mut indices = Vec ::new ( ) ;
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 ] ;
vertices . push ( Vertex {
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 ) ;
}
}
}
}
entities . push ( indices ) ;
}
models . push ( model ::ModelSingleTexture {
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-09-30 20:00:01 +00:00
const MODEL_BUFFER_SIZE :usize = 4 * 4 + 4 * 4 + 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
raw . extend_from_slice ( & AsRef ::< [ f32 ; 4 * 4 ] > ::as_ref ( & mi . normal_transform ) [ .. ] ) ;
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-09-20 00:53:29 +00:00
fn to_uniform_data ( camera : & body ::Camera , pos : glam ::Vec3 ) -> [ f32 ; 16 * 3 + 4 ] {
let proj = camera . proj ( ) ;
let proj_inv = proj . inverse ( ) ;
let view = camera . view ( pos ) ;
let view_inv = view . inverse ( ) ;
let mut raw = [ 0 f32 ; 16 * 3 + 4 ] ;
raw [ .. 16 ] . copy_from_slice ( & AsRef ::< [ f32 ; 16 ] > ::as_ref ( & proj ) [ .. ] ) ;
raw [ 16 .. 32 ] . copy_from_slice ( & AsRef ::< [ f32 ; 16 ] > ::as_ref ( & proj_inv ) [ .. ] ) ;
raw [ 32 .. 48 ] . copy_from_slice ( & AsRef ::< [ f32 ; 16 ] > ::as_ref ( & view_inv ) [ .. ] ) ;
raw [ 48 .. 52 ] . copy_from_slice ( AsRef ::< [ f32 ; 4 ] > ::as_ref ( & view . col ( 3 ) ) ) ;
raw
}
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-09-29 02:10:22 +00:00
let mut indexed_models = Vec ::new ( ) ;
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 . as_ref ( ) ) ) ;
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 ( ) ) ;
indexed_models [ 0 ] . instances . push ( ModelInstance {
2023-09-30 20:00:01 +00:00
transform :glam ::Affine3A ::from_translation ( glam ::vec3 ( 10. , 0. , - 10. ) ) ,
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-29 02:10:22 +00:00
indexed_models [ 1 ] . instances . push ( ModelInstance {
2023-09-30 20:00:01 +00:00
transform :glam ::Affine3A ::from_translation ( glam ::vec3 ( 10. , 5. , 10. ) ) ,
2023-10-04 02:45:01 +00:00
.. Default ::default ( )
2023-09-21 20:02:01 +00:00
} ) ;
2023-09-29 02:10:22 +00:00
indexed_models [ 1 ] . instances . push ( ModelInstance {
2023-09-30 20:00:01 +00:00
transform :glam ::Affine3A ::from_translation ( glam ::vec3 ( 20. , 5. , 10. ) ) ,
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-29 02:10:22 +00:00
indexed_models [ 1 ] . instances . push ( ModelInstance {
2023-09-30 20:00:01 +00:00
transform :glam ::Affine3A ::from_translation ( glam ::vec3 ( 10. , 5. , 20. ) ) ,
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-29 02:10:22 +00:00
indexed_models [ 1 ] . instances . push ( ModelInstance {
2023-09-30 20:00:01 +00:00
transform :glam ::Affine3A ::from_translation ( glam ::vec3 ( 20. , 5. , 20. ) ) ,
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
indexed_models [ 1 ] . instances . push ( ModelInstance {
transform :glam ::Affine3A ::from_translation ( glam ::vec3 ( 15. , 10. , 15. ) ) ,
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-29 02:10:22 +00:00
indexed_models [ 2 ] . instances . push ( ModelInstance {
2023-09-30 23:18:23 +00:00
transform :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. ) ) ,
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-29 02:10:22 +00:00
indexed_models [ 3 ] . instances . push ( ModelInstance {
2023-09-30 20:00:01 +00:00
transform :glam ::Affine3A ::from_translation ( glam ::vec3 ( 0. , 0. , 0. ) ) * glam ::Affine3A ::from_scale ( glam ::vec3 ( 160.0 , 1.0 , 160.0 ) ) ,
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-22 22:19:44 +00:00
let physics = body ::PhysicsState {
2023-09-20 00:53:29 +00:00
spawn_point :glam ::vec3 ( 0.0 , 50.0 , 0.0 ) ,
2023-09-22 22:19:44 +00:00
body : body ::Body ::with_pva ( glam ::vec3 ( 0.0 , 50.0 , 0.0 ) , glam ::vec3 ( 0.0 , 0.0 , 0.0 ) , glam ::vec3 ( 0.0 , - 100.0 , 0.0 ) ) ,
2023-09-08 18:33:16 +00:00
time : 0 ,
2023-10-03 05:45:20 +00:00
style :body ::StyleModifiers ::default ( ) ,
2023-09-18 23:04:08 +00:00
grounded : false ,
2023-10-04 21:15:04 +00:00
contacts : std ::collections ::HashMap ::new ( ) ,
intersects : std ::collections ::HashMap ::new ( ) ,
2023-09-20 00:53:29 +00:00
models : Vec ::new ( ) ,
walk : body ::WalkState ::new ( ) ,
camera : body ::Camera ::from_offset ( glam ::vec3 ( 0.0 , 4.5 - 2.5 , 0.0 ) , ( config . width as f32 ) / ( config . height as f32 ) ) ,
mouse_interpolation : body ::MouseInterpolationState ::new ( ) ,
controls : 0 ,
2023-10-03 05:45:20 +00:00
world :body ::WorldState { } ,
game :body ::GameMechanicsState ::default ( ) ,
2023-10-04 02:42:07 +00:00
modes :Vec ::new ( ) ,
2023-10-04 21:13:25 +00:00
mode_from_mode_id :std ::collections ::HashMap ::new ( ) ,
2023-09-06 21:39:44 +00:00
} ;
2023-09-08 18:33:16 +00:00
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 {
array_stride : std ::mem ::size_of ::< Vertex > ( ) as wgpu ::BufferAddress ,
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-09-20 00:53:29 +00:00
let camera_uniforms = to_uniform_data ( & physics . camera , physics . body . extrapolated_position ( 0 ) ) ;
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 " ) ,
} ) ;
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-04 02:43:41 +00:00
let graphics = GraphicsState {
2023-09-20 00:53:29 +00:00
screen_size : ( config . width , config . height ) ,
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-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-04 02:43:41 +00:00
let mut state = GlobalState {
start_time :Instant ::now ( ) ,
manual_mouse_lock :false ,
graphics ,
physics ,
} ;
2023-09-29 02:10:22 +00:00
let indexed_model_instances = model ::IndexedModelInstances {
textures :Vec ::new ( ) ,
models :indexed_models ,
2023-10-02 22:27:41 +00:00
spawn_point :glam ::Vec3 ::Y * 50.0 ,
2023-10-04 02:42:07 +00:00
modes :Vec ::new ( ) ,
2023-09-29 02:10:22 +00:00
} ;
2023-10-04 02:43:41 +00:00
state . generate_model_physics ( & indexed_model_instances ) ;
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 . physics . clear ( ) ;
self . graphics . clear ( ) ;
2023-10-02 00:18:29 +00:00
self . generate_model_physics ( & indexed_model_instances ) ;
self . generate_model_graphics ( device , queue , indexed_model_instances ) ;
//manual reset
let time = self . physics . time ;
instruction ::InstructionConsumer ::process_instruction ( & mut self . physics , instruction ::TimedInstruction {
time ,
instruction : body ::PhysicsInstruction ::SetSpawnPosition ( spawn_point ) ,
} ) ;
instruction ::InstructionConsumer ::process_instruction ( & mut self . physics , instruction ::TimedInstruction {
time ,
instruction : body ::PhysicsInstruction ::Input ( body ::InputInstruction ::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 ) {
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-09-20 00:53:29 +00:00
_ = > ( ) ,
}
}
2023-10-02 09:40:36 +00:00
fn device_event ( & mut self , window : & winit ::window ::Window , event : winit ::event ::DeviceEvent ) {
2023-09-20 00:53:29 +00:00
//there's no way this is the best way get a timestamp.
let time = self . start_time . elapsed ( ) . as_nanos ( ) as i64 ;
match event {
winit ::event ::DeviceEvent ::Key ( winit ::event ::KeyboardInput {
state ,
scancode : keycode ,
2023-09-06 21:39:44 +00:00
..
2023-09-20 00:53:29 +00:00
} ) = > {
let s = match state {
winit ::event ::ElementState ::Pressed = > true ,
winit ::event ::ElementState ::Released = > false ,
} ;
if let Some ( input_instruction ) = match keycode {
2023-10-02 10:03:07 +00:00
17 = > Some ( InputInstruction ::MoveForward ( s ) ) , //W
30 = > Some ( InputInstruction ::MoveLeft ( s ) ) , //A
31 = > Some ( InputInstruction ::MoveBack ( s ) ) , //S
32 = > Some ( InputInstruction ::MoveRight ( s ) ) , //D
18 = > Some ( InputInstruction ::MoveUp ( s ) ) , //E
16 = > Some ( InputInstruction ::MoveDown ( s ) ) , //Q
57 = > Some ( InputInstruction ::Jump ( s ) ) , //Space
44 = > Some ( InputInstruction ::Zoom ( s ) ) , //Z
19 = > if s { Some ( InputInstruction ::Reset ) } else { None } , //R
01 = > { //Esc
2023-10-02 09:40:36 +00:00
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 ) ;
}
None
} ,
15 = > { //Tab
if s {
self . manual_mouse_lock = false ;
2023-10-04 02:43:41 +00:00
match window . set_cursor_position ( winit ::dpi ::PhysicalPosition ::new ( self . graphics . screen_size . 0 as f32 / 2.0 , self . graphics . screen_size . 1 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 ) ;
None
} ,
_ = > { println! ( " scancode {} " , keycode ) ; None } ,
2023-10-02 10:03:07 +00:00
} {
2023-09-20 00:53:29 +00:00
self . physics . run ( time ) ;
self . physics . process_instruction ( TimedInstruction {
time ,
instruction :PhysicsInstruction ::Input ( input_instruction ) ,
} )
}
} ,
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-04 02:43:41 +00:00
match window . set_cursor_position ( winit ::dpi ::PhysicalPosition ::new ( self . graphics . screen_size . 0 as f32 / 2.0 , self . graphics . screen_size . 1 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.
self . physics . process_instruction ( TimedInstruction {
time ,
instruction :PhysicsInstruction ::Input ( InputInstruction ::MoveMouse ( glam ::ivec2 ( delta . 0 as i32 , delta . 1 as i32 ) ) ) ,
} )
} ,
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-09-20 00:53:29 +00:00
self . physics . run ( time ) ;
self . physics . process_instruction ( TimedInstruction {
time ,
instruction :PhysicsInstruction ::Input ( InputInstruction ::Jump ( true ) ) , //activates the immediate jump path, but the style modifier prevents controls&CONTROL_JUMP bit from being set to auto jump
} )
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 ) ;
self . graphics . screen_size = ( config . width , config . height ) ;
2023-09-20 00:53:29 +00:00
self . physics . camera . set_fov_aspect ( 1.0 , ( config . width as f32 ) / ( config . height as f32 ) ) ;
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-09-08 18:33:16 +00:00
let time = self . start_time . elapsed ( ) . as_nanos ( ) as i64 ;
2023-09-19 06:57:42 +00:00
self . physics . run ( time ) ;
2023-09-06 21:39:44 +00:00
let mut encoder =
device . create_command_encoder ( & wgpu ::CommandEncoderDescriptor { label : None } ) ;
// update rotation
2023-09-20 00:53:29 +00:00
let camera_uniforms = to_uniform_data ( & self . physics . camera , self . physics . body . extrapolated_position ( time ) ) ;
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-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-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
}