2024-02-14 02:02:32 +00:00
use strafesnet_common ::{ map , model , integer , gameplay_attributes } ;
2024-01-31 01:42:41 +00:00
const VALVE_SCALE :f32 = 1.0 / 16.0 ;
fn valve_transform ( v :[ f32 ; 3 ] ) ->integer ::Planar64Vec3 {
integer ::Planar64Vec3 ::try_from ( [ v [ 0 ] * VALVE_SCALE , v [ 2 ] * VALVE_SCALE , - v [ 1 ] * VALVE_SCALE ] ) . unwrap ( )
}
2024-02-14 02:02:32 +00:00
pub fn convert < AcquireTextureId , AcquireMeshId > (
bsp :& vbsp ::Bsp ,
mut acquire_texture_id :AcquireTextureId ,
mut acquire_mesh_id :AcquireMeshId
) ->strafesnet_common ::map ::CompleteMap
where
AcquireTextureId :FnMut ( & str ) ->model ::TextureId ,
AcquireMeshId :FnMut ( & str ) ->model ::MeshId ,
{
let mut unique_render_configs = Vec ::new ( ) ;
let mut unique_attributes = Vec ::new ( ) ;
unique_attributes . push ( gameplay_attributes ::CollisionAttributes ::contact_default ( ) ) ;
const TEMP_TOUCH_ME_ATTRIBUTE :gameplay_attributes ::CollisionAttributesId = gameplay_attributes ::CollisionAttributesId ::new ( 0 ) ;
//declare all prop models to Loader
for prop in bsp . static_props ( ) {
acquire_mesh_id ( prop . model ( ) ) ;
2024-01-31 01:42:41 +00:00
}
2024-02-14 02:02:32 +00:00
//TODO: make the main map one single mesh with a bunch of different physics groups and graphics groups
//the generated MeshIds in here will collide with the Loader Mesh Ids
//but I can't think of a good workaround other than just remapping one later.
let ( meshes , models ) :( Vec < model ::Mesh > , Vec < model ::Model > ) = bsp . models ( ) . enumerate ( ) . map ( | ( mesh_id , world_model ) | {
let mesh_id = model ::MeshId ::new ( mesh_id as u32 ) ;
//non-deduplicated
let mut spam_pos = Vec ::new ( ) ;
let mut spam_tex = Vec ::new ( ) ;
let mut spam_normal = Vec ::new ( ) ;
let mut spam_vertices = Vec ::new ( ) ;
let mut graphics_groups = Vec ::new ( ) ;
let mut physics_group = model ::IndexedPhysicsGroup ::default ( ) ;
let polygon_groups = world_model . faces ( ) . enumerate ( ) . map ( | ( polygon_group_id , face ) | {
let polygon_group_id = model ::PolygonGroupId ::new ( polygon_group_id as u32 ) ;
let face_texture = face . texture ( ) ;
let face_texture_data = face_texture . texture_data ( ) ;
let ( texture_u , texture_v ) = ( glam ::Vec3A ::from_slice ( & face_texture . texture_transforms_u [ 0 .. 3 ] ) , glam ::Vec3A ::from_slice ( & face_texture . texture_transforms_v [ 0 .. 3 ] ) ) ;
let texture_offset = glam ::vec2 ( face_texture . texture_transforms_u [ 3 ] , face_texture . texture_transforms_v [ 3 ] ) ;
let texture_size = glam ::vec2 ( face_texture_data . width as f32 , face_texture_data . height as f32 ) ;
//texture
let texture_id = acquire_texture_id ( face_texture_data . name ( ) ) ; //this is equivalent to a get_or_create pattern because there is a singular no-texture RenderId
//so RenderId==TextureId
//not the most failsafe code but this is just for the map tool lmao
if unique_render_configs . len ( ) = = texture_id . get ( ) as usize {
unique_render_configs . push ( model ::RenderConfig ::texture ( texture_id ) ) ;
} ;
let render_id = model ::RenderConfigId ::new ( texture_id . get ( ) ) ;
//normal
let normal = face . normal ( ) ;
let normal_idx = spam_normal . len ( ) as u32 ;
spam_normal . push ( valve_transform ( < [ f32 ; 3 ] > ::from ( normal ) ) ) ;
let mut indices :Vec < model ::VertexId > = face . vertex_positions ( ) . map ( | vertex_position | {
let vertex_xyz = < [ f32 ; 3 ] > ::from ( vertex_position ) ;
let pos = glam ::Vec3A ::from_array ( vertex_xyz ) ;
let pos_idx = spam_pos . len ( ) ;
spam_pos . push ( valve_transform ( vertex_xyz ) ) ;
//calculate texture coordinates
let tex = ( glam ::vec2 ( pos . dot ( texture_u ) , pos . dot ( texture_v ) ) + texture_offset ) / texture_size ;
let tex_idx = spam_tex . len ( ) as u32 ;
spam_tex . push ( tex ) ;
let vertex_id = model ::VertexId ::new ( spam_vertices . len ( ) as u32 ) ;
spam_vertices . push ( model ::IndexedVertex {
pos :model ::PositionId ::new ( pos_idx as u32 ) ,
tex :model ::TextureCoordinateId ::new ( tex_idx as u32 ) ,
normal :model ::NormalId ::new ( normal_idx ) ,
color :model ::ColorId ::new ( 0 ) ,
} ) ;
vertex_id
2024-01-31 01:42:41 +00:00
} ) . collect ( ) ;
2024-02-14 02:02:32 +00:00
if face . is_visible ( ) {
graphics_groups . push ( model ::IndexedGraphicsGroup {
render :render_id ,
groups :vec ! [ polygon_group_id ] ,
} )
2024-01-31 01:42:41 +00:00
}
2024-02-14 02:02:32 +00:00
physics_group . groups . push ( polygon_group_id ) ;
model ::PolygonGroup ::PolygonList ( model ::PolygonList ::new ( vec! [ indices ] ) )
} ) . collect ( ) ;
(
model ::Mesh {
unique_pos :spam_pos ,
unique_tex :spam_tex ,
unique_normal :spam_normal ,
unique_color :vec ! [ glam ::Vec4 ::ONE ] ,
unique_vertices :spam_vertices ,
polygon_groups ,
graphics_groups ,
physics_groups :vec ! [ physics_group ] ,
} ,
model ::Model {
mesh :mesh_id ,
attributes :TEMP_TOUCH_ME_ATTRIBUTE ,
transform :integer ::Planar64Affine3 ::new (
integer ::Planar64Mat3 ::default ( ) ,
valve_transform ( < [ f32 ; 3 ] > ::from ( world_model . origin ) )
) ,
color :glam ::Vec4 ::ONE ,
} ,
)
} ) . unzip ( ) ;
map ::CompleteMap {
attributes :unique_attributes ,
meshes ,
render_configs :unique_render_configs ,
models ,
modes :strafesnet_common ::gameplay_modes ::Modes ::new ( Vec ::new ( ) ) ,
}
}
2024-01-31 01:42:41 +00:00
2024-02-14 02:02:32 +00:00
/*
//call self.acquire_texture_id for each texture in the mesh
2024-01-31 01:42:41 +00:00
//generate unique meshes
let mut model_map = std ::collections ::HashMap ::with_capacity ( model_dedupe . len ( ) ) ;
let mut prop_models = Vec ::new ( ) ;
for model_name in model_dedupe {
let model_name_lower = model_name . to_lowercase ( ) ;
//.mdl, .vvd, .dx90.vtx
let mut path = std ::path ::PathBuf ::from ( model_name_lower . as_str ( ) ) ;
let file_name = std ::path ::PathBuf ::from ( path . file_stem ( ) . unwrap ( ) ) ;
path . pop ( ) ;
path . push ( file_name ) ;
let mut vvd_path = path . clone ( ) ;
let mut vtx_path = path . clone ( ) ;
vvd_path . set_extension ( " vvd " ) ;
vtx_path . set_extension ( " dx90.vtx " ) ;
match ( bsp . pack . get ( model_name_lower . as_str ( ) ) , bsp . pack . get ( vvd_path . as_os_str ( ) . to_str ( ) . unwrap ( ) ) , bsp . pack . get ( vtx_path . as_os_str ( ) . to_str ( ) . unwrap ( ) ) ) {
( Ok ( Some ( mdl_file ) ) , Ok ( Some ( vvd_file ) ) , Ok ( Some ( vtx_file ) ) ) = > {
match ( vmdl ::mdl ::Mdl ::read ( mdl_file . as_ref ( ) ) , vmdl ::vvd ::Vvd ::read ( vvd_file . as_ref ( ) ) , vmdl ::vtx ::Vtx ::read ( vtx_file . as_ref ( ) ) ) {
( Ok ( mdl ) , Ok ( vvd ) , Ok ( vtx ) ) = > {
let model = vmdl ::Model ::from_parts ( mdl , vtx , vvd ) ;
let texture_paths = model . texture_directories ( ) ;
if texture_paths . len ( ) ! = 1 {
println! ( " WARNING: multiple texture paths " ) ;
}
let skin = model . skin_tables ( ) . nth ( 0 ) . unwrap ( ) ;
let mut spam_pos = Vec ::with_capacity ( model . vertices ( ) . len ( ) ) ;
let mut spam_normal = Vec ::with_capacity ( model . vertices ( ) . len ( ) ) ;
let mut spam_tex = Vec ::with_capacity ( model . vertices ( ) . len ( ) ) ;
let mut spam_vertices = Vec ::with_capacity ( model . vertices ( ) . len ( ) ) ;
for ( i , vertex ) in model . vertices ( ) . iter ( ) . enumerate ( ) {
spam_pos . push ( valve_transform ( < [ f32 ; 3 ] > ::from ( vertex . position ) ) ) ;
spam_normal . push ( valve_transform ( < [ f32 ; 3 ] > ::from ( vertex . normal ) ) ) ;
spam_tex . push ( glam ::Vec2 ::from_array ( vertex . texture_coordinates ) ) ;
spam_vertices . push ( model ::IndexedVertex {
2024-02-14 02:02:32 +00:00
pos :model ::PositionId ::new ( i as u32 ) ,
tex :model ::TextureCoordinateId ::new ( i as u32 ) ,
normal :model ::NormalId ::new ( i as u32 ) ,
color :model ::ColorId ::new ( 0 ) ,
2024-01-31 01:42:41 +00:00
} ) ;
}
let model_id = prop_models . len ( ) ;
model_map . insert ( model_name , model_id ) ;
2024-02-14 02:02:32 +00:00
prop_models . push ( model ::Mesh {
2024-01-31 01:42:41 +00:00
unique_pos :spam_pos ,
unique_normal :spam_normal ,
unique_tex :spam_tex ,
unique_color :vec ! [ glam ::Vec4 ::ONE ] ,
unique_vertices :spam_vertices ,
groups :model . meshes ( ) . map ( | mesh | {
let texture = if let ( Some ( texture_path ) , Some ( texture_name ) ) = ( texture_paths . get ( 0 ) , skin . texture ( mesh . material_index ( ) ) ) {
let mut path = std ::path ::PathBuf ::from ( texture_path . as_str ( ) ) ;
path . push ( texture_name ) ;
let texture_location = path . as_os_str ( ) . to_str ( ) . unwrap ( ) ;
let texture_id = if let Some ( & texture_id ) = texture_id_from_name . get ( texture_location ) {
texture_id
} else {
println! ( " texture! {} " , texture_location ) ;
let texture_id = name_from_texture_id . len ( ) as u32 ;
texture_id_from_name . insert ( texture_location . to_string ( ) , texture_id ) ;
name_from_texture_id . push ( texture_location . to_string ( ) ) ;
texture_id
} ;
Some ( texture_id )
} else {
None
} ;
model ::IndexedGroup {
texture ,
polys :{
//looking at the code, it would seem that the strips are pre-deindexed into triangle lists when calling this function
mesh . vertex_strip_indices ( ) . map ( | strip | {
strip . collect ::< Vec < usize > > ( ) . chunks ( 3 ) . map ( | tri | {
model ::IndexedPolygon { vertices :vec ! [ tri [ 0 ] as u32 , tri [ 1 ] as u32 , tri [ 2 ] as u32 ] }
} ) . collect ::< Vec < model ::IndexedPolygon > > ( )
} ) . flatten ( ) . collect ( )
} ,
}
} ) . collect ( ) ,
instances :Vec ::new ( ) ,
} ) ;
} ,
_ = > println! ( " model_name= {} error " , model_name ) ,
}
} ,
_ = > println! ( " no model name= {} " , model_name ) ,
}
}
//generate model instances
for prop in bsp . static_props ( ) {
let placement = prop . as_prop_placement ( ) ;
if let Some ( & model_index ) = model_map . get ( placement . model ) {
prop_models [ model_index ] . instances . push ( model ::ModelInstance {
transform :integer ::Planar64Affine3 ::new (
integer ::Planar64Mat3 ::try_from (
glam ::Mat3A ::from_diagonal ( glam ::Vec3 ::splat ( placement . scale ) )
//TODO: figure this out
* glam ::Mat3A ::from_quat ( glam ::Quat ::from_xyzw (
placement . rotation . v . x , //b
placement . rotation . v . y , //c
placement . rotation . v . z , //d
placement . rotation . s , //a
) )
) . unwrap ( ) ,
valve_transform ( < [ f32 ; 3 ] > ::from ( placement . origin ) ) ,
) ,
attributes :model ::CollisionAttributes ::Decoration ,
.. Default ::default ( )
} ) ;
} else {
//println!("model not found {}",placement.model);
}
}
//actually add the prop models
prop_models . append ( & mut models ) ;
2024-02-14 02:02:32 +00:00
* /