rbx_loader: some meshes have no polygons LOL

This commit is contained in:
2026-03-05 08:54:10 -08:00
parent 298a7fcbde
commit c44f4863bb
2 changed files with 36 additions and 13 deletions

View File

@@ -70,7 +70,8 @@ impl MeshWithSize{
#[derive(Debug)]
pub enum Error{
RbxMesh(rbx_mesh::mesh::Error)
NoPolygons,
RbxMesh(rbx_mesh::mesh::Error),
}
impl std::fmt::Display for Error{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
@@ -121,6 +122,10 @@ fn ingest_vertices_truncated2(
))).collect()
}
fn new_polygon_list_checked(list:Vec<model::IndexedVertexList>)->Option<PolygonList>{
(!list.is_empty()).then_some(PolygonList::new(list))
}
fn ingest_faces2_lods3(
polygon_groups:&mut Vec<PolygonGroup>,
vertex_id_map:&HashMap<rbx_mesh::mesh::VertexId2,VertexId>,
@@ -128,10 +133,10 @@ fn ingest_faces2_lods3(
lods:&[rbx_mesh::mesh::Lod3],
){
//faces have to be split into polygon groups based on lod
polygon_groups.extend(lods.windows(2).map(|lod_pair|
PolygonGroup::PolygonList(PolygonList::new(faces[lod_pair[0].0 as usize..lod_pair[1].0 as usize].iter().filter_map(|rbx_mesh::mesh::Face2(v0,v1,v2)|
polygon_groups.extend(lods.windows(2).filter_map(|lod_pair|
Some(PolygonGroup::PolygonList(new_polygon_list_checked(faces[lod_pair[0].0 as usize..lod_pair[1].0 as usize].iter().filter_map(|rbx_mesh::mesh::Face2(v0,v1,v2)|
Some(vec![*vertex_id_map.get(&v0)?,*vertex_id_map.get(&v1)?,*vertex_id_map.get(&v2)?])
).collect()))
).collect())?))
))
}
@@ -142,7 +147,7 @@ pub fn convert(roblox_mesh_bytes:&[u8])->Result<MeshWithSize,Error>{
match rbx_mesh::read_versioned(std::io::Cursor::new(roblox_mesh_bytes)).map_err(Error::RbxMesh)?{
rbx_mesh::mesh::Mesh::V1(mesh)=>{
let color_id=mb.acquire_color_id(glam::Vec4::ONE);
polygon_groups.push(PolygonGroup::PolygonList(PolygonList::new(mesh.vertices.chunks_exact(3).filter_map(|trip|{
let polygon_list=new_polygon_list_checked(mesh.vertices.chunks_exact(3).filter_map(|trip|{
let mut ingest_vertex1=|vertex:&rbx_mesh::mesh::Vertex1|{
let vertex=IndexedVertex{
pos:mb.acquire_pos_id(vec3::try_from_f32_array(vertex.pos).ok()?),
@@ -153,7 +158,10 @@ pub fn convert(roblox_mesh_bytes:&[u8])->Result<MeshWithSize,Error>{
Some(mb.acquire_vertex_id(vertex))
};
Some(vec![ingest_vertex1(&trip[0])?,ingest_vertex1(&trip[1])?,ingest_vertex1(&trip[2])?])
}).collect())));
}).collect());
if let Some(polygon_list)=polygon_list{
polygon_groups.push(PolygonGroup::PolygonList(polygon_list));
}
},
rbx_mesh::mesh::Mesh::V2(mesh)=>{
let vertex_id_map=match mesh.header.sizeof_vertex{
@@ -165,9 +173,12 @@ pub fn convert(roblox_mesh_bytes:&[u8])->Result<MeshWithSize,Error>{
rbx_mesh::mesh::SizeOfVertex2::Full=>ingest_vertices2(mesh.vertices,&mut mb),
};
//one big happy group for all the faces
polygon_groups.push(PolygonGroup::PolygonList(PolygonList::new(mesh.faces.into_iter().filter_map(|face|
let polygon_list=new_polygon_list_checked(mesh.faces.into_iter().filter_map(|face|
Some(vec![*vertex_id_map.get(&face.0)?,*vertex_id_map.get(&face.1)?,*vertex_id_map.get(&face.2)?])
).collect())));
).collect());
if let Some(polygon_list)=polygon_list{
polygon_groups.push(PolygonGroup::PolygonList(polygon_list));
}
},
rbx_mesh::mesh::Mesh::V3(mesh)=>{
let vertex_id_map=match mesh.header.sizeof_vertex{
@@ -188,6 +199,9 @@ pub fn convert(roblox_mesh_bytes:&[u8])->Result<MeshWithSize,Error>{
ingest_faces2_lods3(&mut polygon_groups,&vertex_id_map,&mesh.faces,&mesh.lods);
},
}
if polygon_groups.is_empty(){
return Err(Error::NoPolygons);
}
let mesh=mb.build(
polygon_groups,
//these should probably be moved to the model...

View File

@@ -164,6 +164,10 @@ fn build_mesh5(
Ok(())
}
fn new_polygon_list_checked(list:Vec<model::IndexedVertexList>)->Option<PolygonList>{
(!list.is_empty()).then_some(PolygonList::new(list))
}
const NORMAL_FACES:usize=6;
impl std::error::Error for Error{}
pub fn convert(
@@ -210,9 +214,9 @@ pub fn convert(
};
//physics
let polygon_groups_normal_it=polygon_groups_normal_id.into_iter().filter(|group|!group.is_empty()).map(|faces|
let polygon_groups_normal_it=polygon_groups_normal_id.into_iter().filter_map(|faces|
// graphics polygon groups (to be rendered)
PolygonGroup::PolygonList(PolygonList::new(faces))
Some(PolygonGroup::PolygonList(new_polygon_list_checked(faces)?))
);
let polygon_groups:Vec<PolygonGroup>=if !roblox_physics_data.is_empty(){
let physics_data=rbx_mesh::read_physics_data_versioned(
@@ -231,12 +235,12 @@ pub fn convert(
rbx_mesh::physics_data::PhysicsData::CSGPHS(rbx_mesh::physics_data::CSGPHS::V7(meshes))
=>meshes.meshes,
};
let physics_convex_meshes_it=physics_convex_meshes.into_iter().map(|mesh|{
let physics_convex_meshes_it=physics_convex_meshes.into_iter().filter_map(|mesh|{
// this can be factored out of the loop but I am lazy
let color=mb.acquire_color_id(glam::Vec4::ONE);
let tex=mb.acquire_tex_id(glam::Vec2::ZERO);
// physics polygon groups (to do physics)
Ok(PolygonGroup::PolygonList(PolygonList::new(mesh.faces.into_iter().map(|[PhysicsDataVertexId(vertex_id0),PhysicsDataVertexId(vertex_id1),PhysicsDataVertexId(vertex_id2)]|{
let polygons=mesh.faces.into_iter().map(|[PhysicsDataVertexId(vertex_id0),PhysicsDataVertexId(vertex_id1),PhysicsDataVertexId(vertex_id2)]|{
let face=[
mesh.vertices.get(vertex_id0 as usize).ok_or(Error::MissingVertexId(vertex_id0))?,
mesh.vertices.get(vertex_id1 as usize).ok_or(Error::MissingVertexId(vertex_id1))?,
@@ -249,7 +253,12 @@ pub fn convert(
let pos=mb.acquire_pos_id(vec3::try_from_f32_array(vertex_pos.to_array()).map_err(Error::Planar64Vec3)?);
Ok(mb.acquire_vertex_id(IndexedVertex{pos,tex,normal,color}))
}).collect()
}).collect::<Result<_,_>>()?)))
}).collect::<Result<_,_>>();
let polygon_list=match polygons{
Ok(polygons)=>new_polygon_list_checked(polygons)?,
Err(e)=>return Some(Err(e)),
};
Some(Ok(PolygonGroup::PolygonList(polygon_list)))
});
polygon_groups_normal_it.map(Ok).chain(physics_convex_meshes_it).collect::<Result<_,_>>()?
}else{