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 strafesnet_deferred_loader::{loader::Loader,texture::Texture};
|
||||||
|
|
||||||
use crate::data::RobloxMeshBytes;
|
use crate::data::RobloxMeshBytes;
|
||||||
|
use crate::rbx::RobloxFaceTextureDescription;
|
||||||
|
|
||||||
fn read_entire_file(path:impl AsRef<std::path::Path>)->Result<Vec<u8>,std::io::Error>{
|
fn read_entire_file(path:impl AsRef<std::path::Path>)->Result<Vec<u8>,std::io::Error>{
|
||||||
let mut file=std::fs::File::open(path)?;
|
let mut file=std::fs::File::open(path)?;
|
||||||
@ -103,6 +104,7 @@ pub enum MeshType<'a>{
|
|||||||
mesh_data:&'a [u8],
|
mesh_data:&'a [u8],
|
||||||
physics_data:&'a [u8],
|
physics_data:&'a [u8],
|
||||||
size_float_bits:[u32;3],
|
size_float_bits:[u32;3],
|
||||||
|
part_texture_description:[Option<RobloxFaceTextureDescription>;6],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
#[derive(Hash,Eq,PartialEq)]
|
#[derive(Hash,Eq,PartialEq)]
|
||||||
@ -122,12 +124,14 @@ impl MeshIndex<'_>{
|
|||||||
mesh_data:&'a [u8],
|
mesh_data:&'a [u8],
|
||||||
physics_data:&'a [u8],
|
physics_data:&'a [u8],
|
||||||
size:&rbx_dom_weak::types::Vector3,
|
size:&rbx_dom_weak::types::Vector3,
|
||||||
|
part_texture_description:crate::rbx::RobloxPartDescription,
|
||||||
)->MeshIndex<'a>{
|
)->MeshIndex<'a>{
|
||||||
MeshIndex{
|
MeshIndex{
|
||||||
mesh_type:MeshType::Union{
|
mesh_type:MeshType::Union{
|
||||||
mesh_data,
|
mesh_data,
|
||||||
physics_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,
|
content,
|
||||||
}
|
}
|
||||||
@ -152,7 +156,7 @@ impl<'a> Loader for MeshLoader<'a>{
|
|||||||
let data=read_entire_file(file_name)?;
|
let data=read_entire_file(file_name)?;
|
||||||
crate::mesh::convert(RobloxMeshBytes::new(data))?
|
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
|
// decode asset
|
||||||
let size=glam::Vec3::from_array(size_float_bits.map(f32::from_bits));
|
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()){
|
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();
|
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{
|
}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)]
|
#[derive(Clone,Copy)]
|
||||||
struct RobloxTextureTransform{
|
pub struct RobloxTextureTransform{
|
||||||
offset_u:f32,
|
offset_studs_u:f32,
|
||||||
offset_v:f32,
|
offset_studs_v:f32,
|
||||||
scale_u:f32,
|
studs_per_tile_u:f32,
|
||||||
scale_v:f32,
|
studs_per_tile_v:f32,
|
||||||
|
size_u:f32,
|
||||||
|
size_v:f32,
|
||||||
}
|
}
|
||||||
impl std::cmp::Eq for RobloxTextureTransform{}//????
|
#[derive(Clone,Copy,Hash,Eq,PartialEq)]
|
||||||
impl std::default::Default for RobloxTextureTransform{
|
pub struct RobloxTextureTransformBits{
|
||||||
fn default()->Self{
|
offset_studs_u:u32,
|
||||||
Self{offset_u:0.0,offset_v:0.0,scale_u:1.0,scale_v:1.0}
|
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{
|
impl RobloxTextureTransform{
|
||||||
fn hash<H:std::hash::Hasher>(&self,state:&mut H) {
|
fn identity()->Self{
|
||||||
self.offset_u.to_ne_bytes().hash(state);
|
Self{
|
||||||
self.offset_v.to_ne_bytes().hash(state);
|
offset_studs_u:0.0,
|
||||||
self.scale_u.to_ne_bytes().hash(state);
|
offset_studs_v:0.0,
|
||||||
self.scale_v.to_ne_bytes().hash(state);
|
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)]
|
impl core::hash::Hash for RobloxTextureTransform{
|
||||||
struct RobloxFaceTextureDescription{
|
fn hash<H:core::hash::Hasher>(&self,state:&mut H){
|
||||||
render:RenderConfigId,
|
self.to_bits().hash(state);
|
||||||
color:glam::Vec4,
|
}
|
||||||
transform:RobloxTextureTransform,
|
|
||||||
}
|
}
|
||||||
impl std::cmp::Eq for RobloxFaceTextureDescription{}//????
|
#[derive(Clone,Copy,Hash,Eq,PartialEq)]
|
||||||
impl std::hash::Hash for RobloxFaceTextureDescription{
|
pub struct RobloxFaceTextureDescriptionBits{
|
||||||
fn hash<H:std::hash::Hasher>(&self,state:&mut H){
|
render:RenderConfigId,
|
||||||
self.render.hash(state);
|
color:[u32;4],
|
||||||
self.transform.hash(state);
|
transform:RobloxTextureTransformBits,
|
||||||
for &el in self.color.as_ref().iter(){
|
}
|
||||||
el.to_ne_bytes().hash(state);
|
#[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{
|
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{
|
primitives::FaceDescription{
|
||||||
render:self.render,
|
render:self.render,
|
||||||
transform:glam::Affine2::from_translation(
|
transform:self.transform.affine(),
|
||||||
glam::vec2(self.transform.offset_u,self.transform.offset_v)
|
|
||||||
)
|
|
||||||
*glam::Affine2::from_scale(
|
|
||||||
glam::vec2(self.transform.scale_u,self.transform.scale_v)
|
|
||||||
),
|
|
||||||
color:self.color,
|
color:self.color,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
type RobloxPartDescription=[Option<RobloxFaceTextureDescription>;6];
|
pub type RobloxPartDescription=[Option<RobloxFaceTextureDescription>;6];
|
||||||
type RobloxWedgeDescription=[Option<RobloxFaceTextureDescription>;5];
|
type RobloxWedgeDescription=[Option<RobloxFaceTextureDescription>;5];
|
||||||
type RobloxCornerWedgeDescription=[Option<RobloxFaceTextureDescription>;5];
|
type RobloxCornerWedgeDescription=[Option<RobloxFaceTextureDescription>;5];
|
||||||
#[derive(Clone,Eq,Hash,PartialEq)]
|
#[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"{
|
let (roblox_texture_color,roblox_texture_transform)=if decal.class=="Texture"{
|
||||||
//generate tranform
|
//generate tranform
|
||||||
if let (
|
if let (
|
||||||
Some(rbx_dom_weak::types::Variant::Float32(ox)),
|
Some(&rbx_dom_weak::types::Variant::Float32(offset_studs_u)),
|
||||||
Some(rbx_dom_weak::types::Variant::Float32(oy)),
|
Some(&rbx_dom_weak::types::Variant::Float32(offset_studs_v)),
|
||||||
Some(rbx_dom_weak::types::Variant::Float32(sx)),
|
Some(&rbx_dom_weak::types::Variant::Float32(studs_per_tile_u)),
|
||||||
Some(rbx_dom_weak::types::Variant::Float32(sy)),
|
Some(&rbx_dom_weak::types::Variant::Float32(studs_per_tile_v)),
|
||||||
) = (
|
) = (
|
||||||
decal.properties.get("OffsetStudsU"),
|
decal.properties.get("OffsetStudsU"),
|
||||||
decal.properties.get("OffsetStudsV"),
|
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),
|
glam::vec4(decal_color3.r,decal_color3.g,decal_color3.b,1.0-*decal_transparency),
|
||||||
RobloxTextureTransform{
|
RobloxTextureTransform{
|
||||||
offset_u:*ox/(*sx),offset_v:*oy/(*sy),
|
offset_studs_u,
|
||||||
scale_u:size_u/(*sx),scale_v:size_v/(*sy),
|
offset_studs_v,
|
||||||
|
studs_per_tile_u,
|
||||||
|
studs_per_tile_v,
|
||||||
|
size_u,
|
||||||
|
size_v,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}else{
|
}else{
|
||||||
(glam::Vec4::ONE,RobloxTextureTransform::default())
|
(glam::Vec4::ONE,RobloxTextureTransform::identity())
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
(glam::Vec4::ONE,RobloxTextureTransform::default())
|
(glam::Vec4::ONE,RobloxTextureTransform::identity())
|
||||||
};
|
};
|
||||||
part_texture_description[normal_id as usize]=Some(RobloxFaceTextureDescription{
|
part_texture_description[normal_id as usize]=Some(RobloxFaceTextureDescription{
|
||||||
render:render_id,
|
render:render_id,
|
||||||
@ -729,7 +778,7 @@ pub fn convert<'a>(
|
|||||||
physics_data=data.as_ref();
|
physics_data=data.as_ref();
|
||||||
}
|
}
|
||||||
let part_texture_description=get_texture_description(&mut temp_objects,render_config_deferred_loader,dom,object,size);
|
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);
|
let mesh_id=mesh_deferred_loader.acquire_mesh_id(mesh_index);
|
||||||
(MeshAvailability::DeferredUnion(part_texture_description),mesh_id)
|
(MeshAvailability::DeferredUnion(part_texture_description),mesh_id)
|
||||||
},
|
},
|
||||||
|
@ -52,7 +52,12 @@ impl MeshDataNormalChecker{
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for Error{}
|
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;
|
const NORMAL_FACES:usize=6;
|
||||||
let mut polygon_groups_normal_id=vec![Vec::new();NORMAL_FACES];
|
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();
|
let mut mb=strafesnet_common::model::MeshBuilder::new();
|
||||||
// graphics
|
// graphics
|
||||||
let graphics_groups=if !roblox_mesh_data.is_empty(){
|
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(
|
let mesh_data=rbx_mesh::read_mesh_data_versioned(
|
||||||
std::io::Cursor::new(roblox_mesh_data)
|
std::io::Cursor::new(roblox_mesh_data)
|
||||||
).map_err(Error::RobloxMeshData)?;
|
).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);
|
normal_agreement_checker.check(vertex.normal_id);
|
||||||
let pos=mb.acquire_pos_id(vec3::try_from_f32_array(vertex.pos)?);
|
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 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 tex_coord=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 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}))
|
Ok(mb.acquire_vertex_id(IndexedVertex{pos,tex,normal,color}))
|
||||||
}).collect::<Result<Vec<_>,_>>().map_err(Error::Planar64Vec3)?;
|
}).collect::<Result<Vec<_>,_>>().map_err(Error::Planar64Vec3)?;
|
||||||
if let Some(normal_id)=normal_agreement_checker.into_agreed_normal(){
|
if let Some(normal_id)=normal_agreement_checker.into_agreed_normal(){
|
||||||
|
Loading…
x
Reference in New Issue
Block a user