plumb decal into union convert
This commit is contained in:
parent
4313ce036c
commit
c48beced05
@ -4,6 +4,7 @@ use strafesnet_common::model::Mesh;
|
||||
use strafesnet_deferred_loader::{loader::Loader,texture::Texture};
|
||||
|
||||
use crate::data::RobloxMeshBytes;
|
||||
use crate::rbx::RobloxFaceTextureDescription;
|
||||
|
||||
fn read_entire_file(path:impl AsRef<std::path::Path>)->Result<Vec<u8>,std::io::Error>{
|
||||
let mut file=std::fs::File::open(path)?;
|
||||
@ -103,6 +104,7 @@ pub enum MeshType<'a>{
|
||||
mesh_data:&'a [u8],
|
||||
physics_data:&'a [u8],
|
||||
size_float_bits:[u32;3],
|
||||
part_texture_description:[Option<RobloxFaceTextureDescription>;6],
|
||||
},
|
||||
}
|
||||
#[derive(Hash,Eq,PartialEq)]
|
||||
@ -122,12 +124,14 @@ impl MeshIndex<'_>{
|
||||
mesh_data:&'a [u8],
|
||||
physics_data:&'a [u8],
|
||||
size:&rbx_dom_weak::types::Vector3,
|
||||
part_texture_description:crate::rbx::RobloxPartDescription,
|
||||
)->MeshIndex<'a>{
|
||||
MeshIndex{
|
||||
mesh_type:MeshType::Union{
|
||||
mesh_data,
|
||||
physics_data,
|
||||
size_float_bits:[size.x.to_bits(),size.y.to_bits(),size.z.to_bits()]
|
||||
size_float_bits:[size.x.to_bits(),size.y.to_bits(),size.z.to_bits()],
|
||||
part_texture_description,
|
||||
},
|
||||
content,
|
||||
}
|
||||
@ -152,7 +156,7 @@ impl<'a> Loader for MeshLoader<'a>{
|
||||
let data=read_entire_file(file_name)?;
|
||||
crate::mesh::convert(RobloxMeshBytes::new(data))?
|
||||
},
|
||||
MeshType::Union{mut physics_data,mut mesh_data,size_float_bits}=>{
|
||||
MeshType::Union{mut physics_data,mut mesh_data,size_float_bits,part_texture_description}=>{
|
||||
// decode asset
|
||||
let size=glam::Vec3::from_array(size_float_bits.map(f32::from_bits));
|
||||
if !index.content.is_empty()&&(physics_data.is_empty()||mesh_data.is_empty()){
|
||||
@ -176,9 +180,9 @@ impl<'a> Loader for MeshLoader<'a>{
|
||||
mesh_data=data.as_ref();
|
||||
}
|
||||
}
|
||||
crate::union::convert(physics_data,mesh_data,size)?
|
||||
crate::union::convert(physics_data,mesh_data,size,part_texture_description)?
|
||||
}else{
|
||||
crate::union::convert(physics_data,mesh_data,size)?
|
||||
crate::union::convert(physics_data,mesh_data,size,part_texture_description)?
|
||||
}
|
||||
},
|
||||
};
|
||||
|
@ -346,58 +346,103 @@ fn get_attributes(name:&str,can_collide:bool,velocity:Planar64Vec3,model_id:mode
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Copy,PartialEq)]
|
||||
struct RobloxTextureTransform{
|
||||
offset_u:f32,
|
||||
offset_v:f32,
|
||||
scale_u:f32,
|
||||
scale_v:f32,
|
||||
#[derive(Clone,Copy)]
|
||||
pub struct RobloxTextureTransform{
|
||||
offset_studs_u:f32,
|
||||
offset_studs_v:f32,
|
||||
studs_per_tile_u:f32,
|
||||
studs_per_tile_v:f32,
|
||||
size_u:f32,
|
||||
size_v:f32,
|
||||
}
|
||||
impl std::cmp::Eq for RobloxTextureTransform{}//????
|
||||
impl std::default::Default for RobloxTextureTransform{
|
||||
fn default()->Self{
|
||||
Self{offset_u:0.0,offset_v:0.0,scale_u:1.0,scale_v:1.0}
|
||||
}
|
||||
#[derive(Clone,Copy,Hash,Eq,PartialEq)]
|
||||
pub struct RobloxTextureTransformBits{
|
||||
offset_studs_u:u32,
|
||||
offset_studs_v:u32,
|
||||
studs_per_tile_u:u32,
|
||||
studs_per_tile_v:u32,
|
||||
size_u:u32,
|
||||
size_v:u32,
|
||||
}
|
||||
impl std::hash::Hash for RobloxTextureTransform{
|
||||
fn hash<H:std::hash::Hasher>(&self,state:&mut H) {
|
||||
self.offset_u.to_ne_bytes().hash(state);
|
||||
self.offset_v.to_ne_bytes().hash(state);
|
||||
self.scale_u.to_ne_bytes().hash(state);
|
||||
self.scale_v.to_ne_bytes().hash(state);
|
||||
impl RobloxTextureTransform{
|
||||
fn identity()->Self{
|
||||
Self{
|
||||
offset_studs_u:0.0,
|
||||
offset_studs_v:0.0,
|
||||
studs_per_tile_u:1.0,
|
||||
studs_per_tile_v:1.0,
|
||||
size_u:1.0,
|
||||
size_v:1.0,
|
||||
}
|
||||
}
|
||||
pub fn to_bits(self)->RobloxTextureTransformBits{
|
||||
RobloxTextureTransformBits{
|
||||
offset_studs_u:self.offset_studs_u.to_bits(),
|
||||
offset_studs_v:self.offset_studs_v.to_bits(),
|
||||
studs_per_tile_u:self.studs_per_tile_u.to_bits(),
|
||||
studs_per_tile_v:self.studs_per_tile_v.to_bits(),
|
||||
size_u:self.size_u.to_bits(),
|
||||
size_v:self.size_v.to_bits(),
|
||||
}
|
||||
}
|
||||
pub fn affine(&self)->glam::Affine2{
|
||||
glam::Affine2::from_translation(
|
||||
glam::vec2(self.offset_studs_u/self.studs_per_tile_u,self.offset_studs_v/self.studs_per_tile_v)
|
||||
)
|
||||
*glam::Affine2::from_scale(
|
||||
glam::vec2(self.size_u/self.studs_per_tile_u,self.size_v/self.studs_per_tile_v)
|
||||
)
|
||||
}
|
||||
pub fn set_size(&mut self,size_u:f32,size_v:f32){
|
||||
self.size_u=size_u;
|
||||
self.size_v=size_v;
|
||||
}
|
||||
}
|
||||
#[derive(Clone,PartialEq)]
|
||||
struct RobloxFaceTextureDescription{
|
||||
render:RenderConfigId,
|
||||
color:glam::Vec4,
|
||||
transform:RobloxTextureTransform,
|
||||
impl core::hash::Hash for RobloxTextureTransform{
|
||||
fn hash<H:core::hash::Hasher>(&self,state:&mut H){
|
||||
self.to_bits().hash(state);
|
||||
}
|
||||
}
|
||||
impl std::cmp::Eq for RobloxFaceTextureDescription{}//????
|
||||
impl std::hash::Hash for RobloxFaceTextureDescription{
|
||||
fn hash<H:std::hash::Hasher>(&self,state:&mut H){
|
||||
self.render.hash(state);
|
||||
self.transform.hash(state);
|
||||
for &el in self.color.as_ref().iter(){
|
||||
el.to_ne_bytes().hash(state);
|
||||
}
|
||||
}
|
||||
#[derive(Clone,Copy,Hash,Eq,PartialEq)]
|
||||
pub struct RobloxFaceTextureDescriptionBits{
|
||||
render:RenderConfigId,
|
||||
color:[u32;4],
|
||||
transform:RobloxTextureTransformBits,
|
||||
}
|
||||
#[derive(Clone,Copy)]
|
||||
pub struct RobloxFaceTextureDescription{
|
||||
pub render:RenderConfigId,
|
||||
pub color:glam::Vec4,
|
||||
pub transform:RobloxTextureTransform,
|
||||
}
|
||||
impl core::cmp::PartialEq for RobloxFaceTextureDescription{
|
||||
fn eq(&self,other:&Self)->bool{
|
||||
self.to_bits().eq(&other.to_bits())
|
||||
}
|
||||
}
|
||||
impl core::cmp::Eq for RobloxFaceTextureDescription{}
|
||||
impl core::hash::Hash for RobloxFaceTextureDescription{
|
||||
fn hash<H:core::hash::Hasher>(&self,state:&mut H){
|
||||
self.to_bits().hash(state);
|
||||
}
|
||||
}
|
||||
impl RobloxFaceTextureDescription{
|
||||
fn to_face_description(&self)->primitives::FaceDescription{
|
||||
pub fn to_bits(self)->RobloxFaceTextureDescriptionBits{
|
||||
RobloxFaceTextureDescriptionBits{
|
||||
render:self.render,
|
||||
color:self.color.to_array().map(f32::to_bits),
|
||||
transform:self.transform.to_bits(),
|
||||
}
|
||||
}
|
||||
pub fn to_face_description(&self)->primitives::FaceDescription{
|
||||
primitives::FaceDescription{
|
||||
render:self.render,
|
||||
transform:glam::Affine2::from_translation(
|
||||
glam::vec2(self.transform.offset_u,self.transform.offset_v)
|
||||
)
|
||||
*glam::Affine2::from_scale(
|
||||
glam::vec2(self.transform.scale_u,self.transform.scale_v)
|
||||
),
|
||||
transform:self.transform.affine(),
|
||||
color:self.color,
|
||||
}
|
||||
}
|
||||
}
|
||||
type RobloxPartDescription=[Option<RobloxFaceTextureDescription>;6];
|
||||
pub type RobloxPartDescription=[Option<RobloxFaceTextureDescription>;6];
|
||||
type RobloxWedgeDescription=[Option<RobloxFaceTextureDescription>;5];
|
||||
type RobloxCornerWedgeDescription=[Option<RobloxFaceTextureDescription>;5];
|
||||
#[derive(Clone,Eq,Hash,PartialEq)]
|
||||
@ -438,10 +483,10 @@ fn get_texture_description<'a>(
|
||||
let (roblox_texture_color,roblox_texture_transform)=if decal.class=="Texture"{
|
||||
//generate tranform
|
||||
if let (
|
||||
Some(rbx_dom_weak::types::Variant::Float32(ox)),
|
||||
Some(rbx_dom_weak::types::Variant::Float32(oy)),
|
||||
Some(rbx_dom_weak::types::Variant::Float32(sx)),
|
||||
Some(rbx_dom_weak::types::Variant::Float32(sy)),
|
||||
Some(&rbx_dom_weak::types::Variant::Float32(offset_studs_u)),
|
||||
Some(&rbx_dom_weak::types::Variant::Float32(offset_studs_v)),
|
||||
Some(&rbx_dom_weak::types::Variant::Float32(studs_per_tile_u)),
|
||||
Some(&rbx_dom_weak::types::Variant::Float32(studs_per_tile_v)),
|
||||
) = (
|
||||
decal.properties.get("OffsetStudsU"),
|
||||
decal.properties.get("OffsetStudsV"),
|
||||
@ -461,15 +506,19 @@ fn get_texture_description<'a>(
|
||||
(
|
||||
glam::vec4(decal_color3.r,decal_color3.g,decal_color3.b,1.0-*decal_transparency),
|
||||
RobloxTextureTransform{
|
||||
offset_u:*ox/(*sx),offset_v:*oy/(*sy),
|
||||
scale_u:size_u/(*sx),scale_v:size_v/(*sy),
|
||||
offset_studs_u,
|
||||
offset_studs_v,
|
||||
studs_per_tile_u,
|
||||
studs_per_tile_v,
|
||||
size_u,
|
||||
size_v,
|
||||
}
|
||||
)
|
||||
}else{
|
||||
(glam::Vec4::ONE,RobloxTextureTransform::default())
|
||||
(glam::Vec4::ONE,RobloxTextureTransform::identity())
|
||||
}
|
||||
}else{
|
||||
(glam::Vec4::ONE,RobloxTextureTransform::default())
|
||||
(glam::Vec4::ONE,RobloxTextureTransform::identity())
|
||||
};
|
||||
part_texture_description[normal_id as usize]=Some(RobloxFaceTextureDescription{
|
||||
render:render_id,
|
||||
@ -729,7 +778,7 @@ pub fn convert<'a>(
|
||||
physics_data=data.as_ref();
|
||||
}
|
||||
let part_texture_description=get_texture_description(&mut temp_objects,render_config_deferred_loader,dom,object,size);
|
||||
let mesh_index=MeshIndex::union(content,mesh_data,physics_data,size);
|
||||
let mesh_index=MeshIndex::union(content,mesh_data,physics_data,size,part_texture_description.clone());
|
||||
let mesh_id=mesh_deferred_loader.acquire_mesh_id(mesh_index);
|
||||
(MeshAvailability::DeferredUnion(part_texture_description),mesh_id)
|
||||
},
|
||||
|
@ -52,7 +52,12 @@ impl MeshDataNormalChecker{
|
||||
}
|
||||
|
||||
impl std::error::Error for Error{}
|
||||
pub fn convert(roblox_physics_data:&[u8],roblox_mesh_data:&[u8],size:glam::Vec3)->Result<model::Mesh,Error>{
|
||||
pub fn convert(
|
||||
roblox_physics_data:&[u8],
|
||||
roblox_mesh_data:&[u8],
|
||||
size:glam::Vec3,
|
||||
part_texture_description:crate::rbx::RobloxPartDescription,
|
||||
)->Result<model::Mesh,Error>{
|
||||
const NORMAL_FACES:usize=6;
|
||||
let mut polygon_groups_normal_id=vec![Vec::new();NORMAL_FACES];
|
||||
|
||||
@ -60,6 +65,12 @@ pub fn convert(roblox_physics_data:&[u8],roblox_mesh_data:&[u8],size:glam::Vec3)
|
||||
let mut mb=strafesnet_common::model::MeshBuilder::new();
|
||||
// graphics
|
||||
let graphics_groups=if !roblox_mesh_data.is_empty(){
|
||||
// create per-face texture coordinate affine transforms
|
||||
let cube_face_description=part_texture_description.map(|opt|opt.map(|mut t|{
|
||||
t.transform.set_size(1.0,1.0);
|
||||
t.to_face_description()
|
||||
}));
|
||||
|
||||
let mesh_data=rbx_mesh::read_mesh_data_versioned(
|
||||
std::io::Cursor::new(roblox_mesh_data)
|
||||
).map_err(Error::RobloxMeshData)?;
|
||||
@ -79,8 +90,22 @@ pub fn convert(roblox_physics_data:&[u8],roblox_mesh_data:&[u8],size:glam::Vec3)
|
||||
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)));
|
||||
let tex_coord=glam::Vec2::from_array(vertex.tex);
|
||||
let maybe_face_description=&cube_face_description[vertex.normal_id as usize-1];
|
||||
let (tex,color)=match maybe_face_description{
|
||||
Some(face_description)=>{
|
||||
// transform texture coordinates and set decal color
|
||||
let tex=mb.acquire_tex_id(face_description.transform.transform_point2(tex_coord));
|
||||
let color=mb.acquire_color_id(face_description.color);
|
||||
(tex,color)
|
||||
},
|
||||
None=>{
|
||||
// texture coordinates don't matter and pass through mesh vertex color
|
||||
let tex=mb.acquire_tex_id(tex_coord);
|
||||
let color=mb.acquire_color_id(glam::Vec4::from_array(vertex.color.map(|f|f as f32/255.0f32)));
|
||||
(tex,color)
|
||||
},
|
||||
};
|
||||
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(){
|
||||
|
Loading…
x
Reference in New Issue
Block a user