rbx_loader: load unions
This commit is contained in:
parent
93c462aa81
commit
012d2d1837
@ -3,6 +3,7 @@ use rbx_dom_weak::WeakDom;
|
||||
|
||||
mod rbx;
|
||||
mod mesh;
|
||||
mod union;
|
||||
pub mod loader;
|
||||
mod primitives;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use rbx_mesh::mesh::{Vertex2, Vertex2Truncated};
|
||||
use strafesnet_common::{integer::vec3,model::{self, ColorId, IndexedVertex, NormalId, PolygonGroup, PolygonList, PositionId, TextureCoordinateId, VertexId}};
|
||||
use rbx_mesh::mesh::{Vertex2,Vertex2Truncated};
|
||||
use strafesnet_common::{integer::vec3,model::{self,ColorId,IndexedVertex,NormalId,PolygonGroup,PolygonList,PositionId,RenderConfigId,TextureCoordinateId,VertexId}};
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
@ -205,7 +205,13 @@ pub fn convert(roblox_mesh_bytes:crate::data::RobloxMeshBytes)->Result<model::Me
|
||||
unique_vertices,
|
||||
polygon_groups,
|
||||
//these should probably be moved to the model...
|
||||
graphics_groups:Vec::new(),
|
||||
//but what if models want to use the same texture
|
||||
graphics_groups:vec![model::IndexedGraphicsGroup{
|
||||
render:RenderConfigId::new(0),
|
||||
//the lowest lod is highest quality
|
||||
groups:vec![model::PolygonGroupId::new(0)]
|
||||
}],
|
||||
//disable physics
|
||||
physics_groups:Vec::new(),
|
||||
})
|
||||
}
|
||||
|
@ -409,6 +409,7 @@ enum RobloxBasePartDescription{
|
||||
enum Shape{
|
||||
Primitive(primitives::Primitives),
|
||||
MeshPart,
|
||||
PhysicsData,
|
||||
}
|
||||
enum MeshAvailability{
|
||||
Immediate,
|
||||
@ -444,6 +445,7 @@ pub fn convert<'a>(
|
||||
let mut primitive_models_deferred_attributes=Vec::new();
|
||||
let mut primitive_meshes=Vec::new();
|
||||
let mut mesh_id_from_description=HashMap::new();
|
||||
let mut mesh_id_from_physics_data=HashMap::<&[u8],_>::new();
|
||||
|
||||
//just going to leave it like this for now instead of reworking the data structures for this whole thing
|
||||
let textureless_render_group=render_config_deferred_loader.acquire_render_config_id(None);
|
||||
@ -469,7 +471,7 @@ pub fn convert<'a>(
|
||||
object.properties.get("CanCollide"),
|
||||
)
|
||||
{
|
||||
let model_transform=planar64_affine3_from_roblox(cf,size);
|
||||
let mut model_transform=planar64_affine3_from_roblox(cf,size);
|
||||
|
||||
if model_transform.matrix3.det().is_zero(){
|
||||
let mut parent_ref=object.parent();
|
||||
@ -501,6 +503,7 @@ pub fn convert<'a>(
|
||||
"WedgePart"=>Shape::Primitive(primitives::Primitives::Wedge),
|
||||
"CornerWedgePart"=>Shape::Primitive(primitives::Primitives::CornerWedge),
|
||||
"MeshPart"=>Shape::MeshPart,
|
||||
"UnionOperation"=>Shape::PhysicsData,
|
||||
_=>{
|
||||
println!("Unsupported BasePart ClassName={}; defaulting to cube",object.class);
|
||||
Shape::Primitive(primitives::Primitives::Cube)
|
||||
@ -695,6 +698,41 @@ pub fn convert<'a>(
|
||||
}else{
|
||||
panic!("Mesh has no Mesh or Texture");
|
||||
},
|
||||
Shape::PhysicsData=>{
|
||||
//The union mesh is sized already
|
||||
model_transform=planar64_affine3_from_roblox(cf,&rbx_dom_weak::types::Vector3{x:2.0,y:2.0,z:2.0});
|
||||
if let Some(rbx_dom_weak::types::Variant::BinaryString(data))=object.properties.get("PhysicsData"){
|
||||
let physics_data=data.as_ref();
|
||||
let mesh_id=if let Some(&mesh_id)=mesh_id_from_physics_data.get(physics_data){
|
||||
mesh_id
|
||||
}else{
|
||||
match crate::union::convert(physics_data){
|
||||
Ok(mesh)=>{
|
||||
let mesh_id=model::MeshId::new(primitive_meshes.len() as u32);
|
||||
primitive_meshes.push(mesh);
|
||||
mesh_id_from_physics_data.insert(physics_data,mesh_id);
|
||||
mesh_id
|
||||
},
|
||||
Err(e)=>{
|
||||
model_transform=planar64_affine3_from_roblox(cf,size);
|
||||
if !matches!(e,crate::union::Error::Block){
|
||||
println!("Union mesh decode error {e:?}");
|
||||
}
|
||||
*mesh_id_from_description.entry(RobloxBasePartDescription::Part(RobloxPartDescription::default()))
|
||||
.or_insert_with(||{
|
||||
let mesh_id=model::MeshId::new(primitive_meshes.len() as u32);
|
||||
let mesh=primitives::unit_cube(textureless_render_group);
|
||||
primitive_meshes.push(mesh);
|
||||
mesh_id
|
||||
})
|
||||
},
|
||||
}
|
||||
};
|
||||
(MeshAvailability::Immediate,mesh_id)
|
||||
}else{
|
||||
panic!("Mesh has no Mesh or Texture");
|
||||
}
|
||||
},
|
||||
};
|
||||
let model_deferred_attributes=ModelDeferredAttributes{
|
||||
mesh:mesh_id,
|
||||
@ -766,12 +804,10 @@ impl PartialMap1{
|
||||
.entry(render).or_insert_with(||{
|
||||
let mesh_id=model::MeshId::new(self.primitive_meshes.len() as u32);
|
||||
let mut mesh_clone=mesh_with_aabb.mesh.clone();
|
||||
//add a render group lool
|
||||
mesh_clone.graphics_groups.push(model::IndexedGraphicsGroup{
|
||||
render,
|
||||
//the lowest lod is highest quality
|
||||
groups:vec![model::PolygonGroupId::new(0)]
|
||||
});
|
||||
//set the render group lool
|
||||
if let Some(graphics_group)=mesh_clone.graphics_groups.first_mut(){
|
||||
graphics_group.render=render;
|
||||
}
|
||||
self.primitive_meshes.push(mesh_clone);
|
||||
mesh_id
|
||||
}),
|
||||
|
126
lib/rbx_loader/src/union.rs
Normal file
126
lib/rbx_loader/src/union.rs
Normal file
@ -0,0 +1,126 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use strafesnet_common::model::{self, ColorId, IndexedVertex, NormalId, PolygonGroup, PolygonGroupId, PolygonList, PositionId, RenderConfigId, TextureCoordinateId, VertexId};
|
||||
use strafesnet_common::integer::vec3;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub enum Error{
|
||||
Block,
|
||||
MissingVertexId(u32),
|
||||
Planar64Vec3(strafesnet_common::integer::Planar64TryFromFloatError),
|
||||
RobloxPhysicsData(rbx_mesh::physics_data::Error),
|
||||
}
|
||||
impl std::fmt::Display for Error{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
write!(f,"{self:?}")
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Error{}
|
||||
pub fn convert(roblox_physics_data:&[u8])->Result<model::Mesh,Error>{
|
||||
if let b""=roblox_physics_data{
|
||||
return Err(Error::Block);
|
||||
}
|
||||
let mut cursor=std::io::Cursor::new(roblox_physics_data);
|
||||
let physics_data:rbx_mesh::physics_data::PhysicsData=rbx_mesh::read_physics_data(&mut cursor).map_err(Error::RobloxPhysicsData)?;
|
||||
assert_eq!(cursor.position(),cursor.into_inner().len() as u64);
|
||||
let meshes=match physics_data{
|
||||
rbx_mesh::physics_data::PhysicsData::CSGK(_)
|
||||
|rbx_mesh::physics_data::PhysicsData::CSGPHS(rbx_mesh::physics_data::CSGPHS::Block)
|
||||
=>return Err(Error::Block),
|
||||
rbx_mesh::physics_data::PhysicsData::CSGPHS(rbx_mesh::physics_data::CSGPHS::Meshes3(meshes))
|
||||
|rbx_mesh::physics_data::PhysicsData::CSGPHS(rbx_mesh::physics_data::CSGPHS::Meshes5(meshes))
|
||||
=>meshes.meshes,
|
||||
rbx_mesh::physics_data::PhysicsData::CSGPHS(rbx_mesh::physics_data::CSGPHS::PhysicsInfoMesh(pim))
|
||||
=>vec![pim.mesh],
|
||||
};
|
||||
let mut unique_pos=Vec::new();
|
||||
let mut pos_id_from=HashMap::new();
|
||||
let mut unique_tex=Vec::new();
|
||||
let mut tex_id_from=HashMap::new();
|
||||
let mut unique_normal=Vec::new();
|
||||
let mut normal_id_from=HashMap::new();
|
||||
let mut unique_color=Vec::new();
|
||||
let mut color_id_from=HashMap::new();
|
||||
let mut unique_vertices=Vec::new();
|
||||
let mut vertex_id_from=HashMap::new();
|
||||
let mut acquire_pos_id=|pos|{
|
||||
let p=vec3::try_from_f32_array(pos).map_err(Error::Planar64Vec3)?;
|
||||
Ok(PositionId::new(*pos_id_from.entry(p).or_insert_with(||{
|
||||
let pos_id=unique_pos.len();
|
||||
unique_pos.push(p);
|
||||
pos_id
|
||||
}) as u32))
|
||||
};
|
||||
let mut acquire_tex_id=|tex|{
|
||||
let h=bytemuck::cast::<[f32;2],[u32;2]>(tex);
|
||||
TextureCoordinateId::new(*tex_id_from.entry(h).or_insert_with(||{
|
||||
let tex_id=unique_tex.len();
|
||||
unique_tex.push(glam::Vec2::from_array(tex));
|
||||
tex_id
|
||||
}) as u32)
|
||||
};
|
||||
let mut acquire_normal_id=|normal|{
|
||||
let n=vec3::try_from_f32_array(normal).map_err(Error::Planar64Vec3)?;
|
||||
Ok(NormalId::new(*normal_id_from.entry(n).or_insert_with(||{
|
||||
let normal_id=unique_normal.len();
|
||||
unique_normal.push(n);
|
||||
normal_id
|
||||
}) as u32))
|
||||
};
|
||||
let mut acquire_color_id=|color|{
|
||||
let h=bytemuck::cast::<[f32;4],[u32;4]>(color);
|
||||
ColorId::new(*color_id_from.entry(h).or_insert_with(||{
|
||||
let color_id=unique_color.len();
|
||||
unique_color.push(glam::Vec4::from_array(color));
|
||||
color_id
|
||||
}) as u32)
|
||||
};
|
||||
let mut acquire_vertex_id=|vertex:IndexedVertex|{
|
||||
VertexId::new(*vertex_id_from.entry(vertex.clone()).or_insert_with(||{
|
||||
let vertex_id=unique_vertices.len();
|
||||
unique_vertices.push(vertex);
|
||||
vertex_id
|
||||
}) as u32)
|
||||
};
|
||||
let color=acquire_color_id([1.0f32;4]);
|
||||
let tex=acquire_tex_id([0.0f32;2]);
|
||||
let polygon_groups:Vec<PolygonGroup>=meshes.into_iter().map(|mesh|{
|
||||
Ok(PolygonGroup::PolygonList(PolygonList::new(mesh.faces.into_iter().map(|[vertex_id0,vertex_id1,vertex_id2]|{
|
||||
let v0=mesh.vertices.get(vertex_id0.0 as usize).ok_or(Error::MissingVertexId(vertex_id0.0))?;
|
||||
let v1=mesh.vertices.get(vertex_id1.0 as usize).ok_or(Error::MissingVertexId(vertex_id1.0))?;
|
||||
let v2=mesh.vertices.get(vertex_id2.0 as usize).ok_or(Error::MissingVertexId(vertex_id2.0))?;
|
||||
let vertex_norm=(glam::Vec3::from_slice(v1)-glam::Vec3::from_slice(v0))
|
||||
.cross(glam::Vec3::from_slice(v2)-glam::Vec3::from_slice(v0)).to_array();
|
||||
let mut ingest_vertex_id=|&vertex_pos:&[f32;3]|Ok(acquire_vertex_id(IndexedVertex{
|
||||
pos:acquire_pos_id(vertex_pos)?,
|
||||
tex,
|
||||
normal:acquire_normal_id(vertex_norm)?,
|
||||
color,
|
||||
}));
|
||||
Ok(vec![
|
||||
ingest_vertex_id(v0)?,
|
||||
ingest_vertex_id(v1)?,
|
||||
ingest_vertex_id(v2)?,
|
||||
])
|
||||
}).collect::<Result<_,_>>()?)))
|
||||
}).collect::<Result<_,_>>()?;
|
||||
let graphics_groups=vec![model::IndexedGraphicsGroup{
|
||||
render:RenderConfigId::new(0),
|
||||
groups:(0..polygon_groups.len()).map(|id|PolygonGroupId::new(id as u32)).collect()
|
||||
}];
|
||||
let physics_groups=(0..polygon_groups.len()).map(|id|model::IndexedPhysicsGroup{
|
||||
groups:vec![PolygonGroupId::new(id as u32)]
|
||||
}).collect();
|
||||
Ok(model::Mesh{
|
||||
unique_pos,
|
||||
unique_normal,
|
||||
unique_tex,
|
||||
unique_color,
|
||||
unique_vertices,
|
||||
polygon_groups,
|
||||
graphics_groups,
|
||||
physics_groups,
|
||||
})
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user