use std::collections::HashMap; use rbx_mesh::mesh::{Vertex2, Vertex2Truncated}; use strafesnet_common::{integer::Planar64Vec3,model::{self, ColorId, IndexedVertex, NormalId, PolygonGroup, PolygonList, PositionId, TextureCoordinateId, VertexId}}; #[derive(Debug)] pub enum Error{ Planar64Vec3(strafesnet_common::integer::Planar64TryFromFloatError), RbxMesh(rbx_mesh::mesh::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{} fn ingest_vertices2< AcquirePosId, AcquireTexId, AcquireNormalId, AcquireColorId, AcquireVertexId, >( vertices:Vec, acquire_pos_id:&mut AcquirePosId, acquire_tex_id:&mut AcquireTexId, acquire_normal_id:&mut AcquireNormalId, acquire_color_id:&mut AcquireColorId, acquire_vertex_id:&mut AcquireVertexId, )->Result,Error> where AcquirePosId:FnMut([f32;3])->Result, AcquireTexId:FnMut([f32;2])->TextureCoordinateId, AcquireNormalId:FnMut([f32;3])->Result, AcquireColorId:FnMut([f32;4])->ColorId, AcquireVertexId:FnMut(IndexedVertex)->VertexId, { //this monster is collecting a map of old_vertices_index -> unique_vertices_index //while also doing the inserting unique entries into lists simultaneously Ok(vertices.into_iter().enumerate().map(|(vertex_id,vertex)|Ok(( rbx_mesh::mesh::VertexId2(vertex_id as u32), acquire_vertex_id(IndexedVertex{ pos:acquire_pos_id(vertex.pos)?, tex:acquire_tex_id(vertex.tex), normal:acquire_normal_id(vertex.norm)?, color:acquire_color_id(vertex.color.map(|f|f as f32/255.0f32)) }), ))).collect::>()?) } fn ingest_vertices_truncated2< AcquirePosId, AcquireTexId, AcquireNormalId, AcquireVertexId, >( vertices:Vec, acquire_pos_id:&mut AcquirePosId, acquire_tex_id:&mut AcquireTexId, acquire_normal_id:&mut AcquireNormalId, static_color_id:ColorId,//pick one color and fill everything with it acquire_vertex_id:&mut AcquireVertexId, )->Result,Error> where AcquirePosId:FnMut([f32;3])->Result, AcquireTexId:FnMut([f32;2])->TextureCoordinateId, AcquireNormalId:FnMut([f32;3])->Result, AcquireVertexId:FnMut(IndexedVertex)->VertexId, { //this monster is collecting a map of old_vertices_index -> unique_vertices_index //while also doing the inserting unique entries into lists simultaneously Ok(vertices.into_iter().enumerate().map(|(vertex_id,vertex)|Ok(( rbx_mesh::mesh::VertexId2(vertex_id as u32), acquire_vertex_id(IndexedVertex{ pos:acquire_pos_id(vertex.pos)?, tex:acquire_tex_id(vertex.tex), normal:acquire_normal_id(vertex.norm)?, color:static_color_id }), ))).collect::>()?) } fn ingest_faces2_lods3( polygon_groups:&mut Vec, vertex_id_map:&HashMap, faces:&Vec, lods:&Vec ){ //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().map(|face| vec![vertex_id_map[&face.0],vertex_id_map[&face.1],vertex_id_map[&face.2]] ).collect())) )) } pub fn convert(roblox_mesh_bytes:crate::data::RobloxMeshBytes)->Result{ //generate that mesh boi 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 polygon_groups=Vec::new(); let mut acquire_pos_id=|pos|{ let p=Planar64Vec3::try_from(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=Planar64Vec3::try_from(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) }; match rbx_mesh::read_versioned(roblox_mesh_bytes.cursor()).map_err(Error::RbxMesh)?{ rbx_mesh::mesh::VersionedMesh::Version1(mesh)=>{ let color_id=acquire_color_id([1.0f32;4]); polygon_groups.push(PolygonGroup::PolygonList(PolygonList::new(mesh.vertices.chunks_exact(3).map(|trip|{ let mut ingest_vertex1=|vertex:&rbx_mesh::mesh::Vertex1|Ok(acquire_vertex_id(IndexedVertex{ pos:acquire_pos_id(vertex.pos)?, tex:acquire_tex_id([vertex.tex[0],vertex.tex[1]]), normal:acquire_normal_id(vertex.norm)?, color:color_id, })); Ok(vec![ingest_vertex1(&trip[0])?,ingest_vertex1(&trip[1])?,ingest_vertex1(&trip[2])?]) }).collect::>()?))); }, rbx_mesh::mesh::VersionedMesh::Version2(mesh)=>{ let vertex_id_map=match mesh.header.sizeof_vertex{ rbx_mesh::mesh::SizeOfVertex2::Truncated=>{ //pick white and make all the vertices white let color_id=acquire_color_id([1.0f32;4]); ingest_vertices_truncated2(mesh.vertices_truncated,&mut acquire_pos_id,&mut acquire_tex_id,&mut acquire_normal_id,color_id,&mut acquire_vertex_id) }, rbx_mesh::mesh::SizeOfVertex2::Full=>ingest_vertices2(mesh.vertices,&mut acquire_pos_id,&mut acquire_tex_id,&mut acquire_normal_id,&mut acquire_color_id,&mut acquire_vertex_id), }?; //one big happy group for all the faces polygon_groups.push(PolygonGroup::PolygonList(PolygonList::new(mesh.faces.into_iter().map(|face| vec![vertex_id_map[&face.0],vertex_id_map[&face.1],vertex_id_map[&face.2]] ).collect()))); }, rbx_mesh::mesh::VersionedMesh::Version3(mesh)=>{ let vertex_id_map=match mesh.header.sizeof_vertex{ rbx_mesh::mesh::SizeOfVertex2::Truncated=>{ let color_id=acquire_color_id([1.0f32;4]); ingest_vertices_truncated2(mesh.vertices_truncated,&mut acquire_pos_id,&mut acquire_tex_id,&mut acquire_normal_id,color_id,&mut acquire_vertex_id) }, rbx_mesh::mesh::SizeOfVertex2::Full=>ingest_vertices2(mesh.vertices,&mut acquire_pos_id,&mut acquire_tex_id,&mut acquire_normal_id,&mut acquire_color_id,&mut acquire_vertex_id), }?; ingest_faces2_lods3(&mut polygon_groups,&vertex_id_map,&mesh.faces,&mesh.lods); }, rbx_mesh::mesh::VersionedMesh::Version4(mesh)=>{ let vertex_id_map=ingest_vertices2( mesh.vertices,&mut acquire_pos_id,&mut acquire_tex_id,&mut acquire_normal_id,&mut acquire_color_id,&mut acquire_vertex_id )?; ingest_faces2_lods3(&mut polygon_groups,&vertex_id_map,&mesh.faces,&mesh.lods); }, rbx_mesh::mesh::VersionedMesh::Version5(mesh)=>{ let vertex_id_map=ingest_vertices2( mesh.vertices,&mut acquire_pos_id,&mut acquire_tex_id,&mut acquire_normal_id,&mut acquire_color_id,&mut acquire_vertex_id )?; ingest_faces2_lods3(&mut polygon_groups,&vertex_id_map,&mesh.faces,&mesh.lods); }, } Ok(model::Mesh{ unique_pos, unique_normal, unique_tex, unique_color, unique_vertices, polygon_groups, //these should probably be moved to the model... graphics_groups:Vec::new(), physics_groups:Vec::new(), }) }