generate union graphics mesh
This commit is contained in:
parent
15b8a2c54e
commit
0a6b2423e2
@ -1,6 +1,5 @@
|
|||||||
use std::collections::HashMap;
|
use rbx_mesh::mesh_data::NormalId2 as MeshDataNormalId2;
|
||||||
|
use strafesnet_common::model::{self,IndexedVertex,PolygonGroup,PolygonGroupId,PolygonList,RenderConfigId};
|
||||||
use strafesnet_common::model::{self, ColorId, IndexedVertex, NormalId, PolygonGroup, PolygonGroupId, PolygonList, PositionId, RenderConfigId, TextureCoordinateId, VertexId};
|
|
||||||
use strafesnet_common::integer::vec3;
|
use strafesnet_common::integer::vec3;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[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{}
|
impl std::error::Error for Error{}
|
||||||
pub fn convert(roblox_physics_data:&[u8],roblox_mesh_data:&[u8])->Result<model::Mesh,Error>{
|
pub fn convert(roblox_physics_data:&[u8],roblox_mesh_data:&[u8])->Result<model::Mesh,Error>{
|
||||||
match (roblox_physics_data,roblox_mesh_data){
|
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))
|
rbx_mesh::physics_data::PhysicsData::CSGPHS(rbx_mesh::physics_data::CSGPHS::PhysicsInfoMesh(pim))
|
||||||
=>vec![pim.mesh],
|
=>vec![pim.mesh],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// build graphics and physics meshes
|
||||||
let mut mb=strafesnet_common::model::MeshBuilder::new();
|
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 color=mb.acquire_color_id(glam::Vec4::ONE);
|
||||||
let tex=mb.acquire_tex_id(glam::Vec2::ZERO);
|
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]|{
|
Ok(PolygonGroup::PolygonList(PolygonList::new(mesh.faces.into_iter().map(|[vertex_id0,vertex_id1,vertex_id2]|{
|
||||||
let face=[
|
let face=[
|
||||||
mesh.vertices.get(vertex_id0.0 as usize).ok_or(Error::MissingVertexId(vertex_id0.0))?,
|
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}))
|
Ok(mb.acquire_vertex_id(IndexedVertex{pos,tex,normal,color}))
|
||||||
}).collect()
|
}).collect()
|
||||||
}).collect::<Result<_,_>>()?)))
|
}).collect::<Result<_,_>>()?)))
|
||||||
}).collect::<Result<_,_>>()?;
|
})).collect::<Result<_,_>>()?;
|
||||||
let graphics_groups=vec![model::IndexedGraphicsGroup{
|
let physics_groups=(NORMAL_FACES..polygon_groups.len()).map(|id|model::IndexedPhysicsGroup{
|
||||||
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)]
|
groups:vec![PolygonGroupId::new(id as u32)]
|
||||||
}).collect();
|
}).collect();
|
||||||
Ok(mb.build(
|
Ok(mb.build(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user