generate union graphics mesh

This commit is contained in:
Quaternions 2025-01-30 09:12:58 -08:00
parent 15b8a2c54e
commit 0a6b2423e2

@ -1,6 +1,5 @@
use std::collections::HashMap;
use strafesnet_common::model::{self, ColorId, IndexedVertex, NormalId, PolygonGroup, PolygonGroupId, PolygonList, PositionId, RenderConfigId, TextureCoordinateId, VertexId};
use rbx_mesh::mesh_data::NormalId2 as MeshDataNormalId2;
use strafesnet_common::model::{self,IndexedVertex,PolygonGroup,PolygonGroupId,PolygonList,RenderConfigId};
use strafesnet_common::integer::vec3;
#[allow(dead_code)]
@ -19,6 +18,40 @@ impl std::fmt::Display for Error{
}
}
// wacky state machine to make sure all vertices in a face agree upon what NormalId to use.
// Roblox duplicates this information per vertex when it should only exist per-face.
enum MeshDataNormalStatus{
Agree(MeshDataNormalId2),
Conflicting,
}
struct MeshDataNormalChecker{
status:Option<MeshDataNormalStatus>,
}
impl MeshDataNormalChecker{
fn new()->Self{
Self{status:None}
}
fn check(&mut self,normal:MeshDataNormalId2){
self.status=match self.status.take(){
None=>Some(MeshDataNormalStatus::Agree(normal)),
Some(MeshDataNormalStatus::Agree(old_normal))=>{
if old_normal==normal{
Some(MeshDataNormalStatus::Agree(old_normal))
}else{
Some(MeshDataNormalStatus::Conflicting)
}
},
Some(MeshDataNormalStatus::Conflicting)=>Some(MeshDataNormalStatus::Conflicting),
};
}
fn into_agreed_normal(self)->Option<MeshDataNormalId2>{
self.status.and_then(|status|match status{
MeshDataNormalStatus::Agree(normal)=>Some(normal),
MeshDataNormalStatus::Conflicting=>None,
})
}
}
impl std::error::Error for Error{}
pub fn convert(roblox_physics_data:&[u8],roblox_mesh_data:&[u8])->Result<model::Mesh,Error>{
match (roblox_physics_data,roblox_mesh_data){
@ -52,10 +85,48 @@ pub fn convert(roblox_physics_data:&[u8],roblox_mesh_data:&[u8])->Result<model::
rbx_mesh::physics_data::PhysicsData::CSGPHS(rbx_mesh::physics_data::CSGPHS::PhysicsInfoMesh(pim))
=>vec![pim.mesh],
};
// build graphics and physics meshes
let mut mb=strafesnet_common::model::MeshBuilder::new();
// graphics
const NORMAL_FACES:usize=6;
let mut polygon_groups_normal_id=vec![Vec::new();NORMAL_FACES];
for [vertex_id0,vertex_id1,vertex_id2] in graphics_mesh.faces{
let face=[
graphics_mesh.vertices.get(vertex_id0.0 as usize).ok_or(Error::MissingVertexId(vertex_id0.0))?,
graphics_mesh.vertices.get(vertex_id1.0 as usize).ok_or(Error::MissingVertexId(vertex_id1.0))?,
graphics_mesh.vertices.get(vertex_id2.0 as usize).ok_or(Error::MissingVertexId(vertex_id2.0))?,
];
let mut normal_agreement_checker=MeshDataNormalChecker::new();
let face=face.into_iter().map(|vertex|{
normal_agreement_checker.check(vertex.normal_id);
let pos=mb.acquire_pos_id(vec3::try_from_f32_array(vertex.pos)?);
let normal=mb.acquire_normal_id(vec3::try_from_f32_array(vertex.norm)?);
let tex=mb.acquire_tex_id(glam::Vec2::from_array(vertex.tex));
let color=mb.acquire_color_id(glam::Vec4::from_array(vertex.color.map(|f|f as f32/255.0f32)));
Ok(mb.acquire_vertex_id(IndexedVertex{pos,tex,normal,color}))
}).collect::<Result<Vec<_>,_>>().map_err(Error::Planar64Vec3)?;
if let Some(normal_id)=normal_agreement_checker.into_agreed_normal(){
polygon_groups_normal_id[normal_id as usize-1].push(face);
}else{
panic!("Empty face!");
}
}
let graphics_groups=(0..polygon_groups_normal_id.len()).map(|polygon_group_id|{
model::IndexedGraphicsGroup{
render:RenderConfigId::new(0),
groups:vec![PolygonGroupId::new(polygon_group_id as u32)]
}
}).collect();
//physics
let color=mb.acquire_color_id(glam::Vec4::ONE);
let tex=mb.acquire_tex_id(glam::Vec2::ZERO);
let polygon_groups:Vec<PolygonGroup>=physics_convex_meshes.into_iter().map(|mesh|{
let polygon_groups:Vec<PolygonGroup>=polygon_groups_normal_id.into_iter().map(|faces|
// graphics polygon groups (to be rendered)
Ok(PolygonGroup::PolygonList(PolygonList::new(faces)))
).chain(physics_convex_meshes.into_iter().map(|mesh|{
// physics polygon groups (to do physics)
Ok(PolygonGroup::PolygonList(PolygonList::new(mesh.faces.into_iter().map(|[vertex_id0,vertex_id1,vertex_id2]|{
let face=[
mesh.vertices.get(vertex_id0.0 as usize).ok_or(Error::MissingVertexId(vertex_id0.0))?,
@ -70,12 +141,8 @@ pub fn convert(roblox_physics_data:&[u8],roblox_mesh_data:&[u8])->Result<model::
Ok(mb.acquire_vertex_id(IndexedVertex{pos,tex,normal,color}))
}).collect()
}).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{
})).collect::<Result<_,_>>()?;
let physics_groups=(NORMAL_FACES..polygon_groups.len()).map(|id|model::IndexedPhysicsGroup{
groups:vec![PolygonGroupId::new(id as u32)]
}).collect();
Ok(mb.build(