Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
b2d035bd24 | |||
fef16b4721 | |||
aed0a4cfcf | |||
c8813337fb | |||
1464c2442d | |||
15e9592897 | |||
3399aef275 | |||
39b3b64720 | |||
9adc7e96fe |
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -1955,9 +1955,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rbx_mesh"
|
name = "rbx_mesh"
|
||||||
version = "0.1.2"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "864ead0e98afce28c960f653d6203483834890d07f87b60e2f01415530a2fe9d"
|
checksum = "1205fdae1f9a8bfd5d8fbe6036066673d530ee392f7840d6f8a24e763559c7fd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"binrw",
|
"binrw",
|
||||||
"lazy-regex",
|
"lazy-regex",
|
||||||
|
@ -15,7 +15,7 @@ glam = "0.29.0"
|
|||||||
lazy-regex = "3.1.0"
|
lazy-regex = "3.1.0"
|
||||||
rbx_binary = { version = "0.7.4", registry = "strafesnet" }
|
rbx_binary = { version = "0.7.4", registry = "strafesnet" }
|
||||||
rbx_dom_weak = { version = "2.7.0", registry = "strafesnet" }
|
rbx_dom_weak = { version = "2.7.0", registry = "strafesnet" }
|
||||||
rbx_mesh = "0.1.2"
|
rbx_mesh = "0.2.0"
|
||||||
rbx_reflection_database = { version = "0.2.10", registry = "strafesnet" }
|
rbx_reflection_database = { version = "0.2.10", registry = "strafesnet" }
|
||||||
rbx_xml = { version = "0.13.3", registry = "strafesnet" }
|
rbx_xml = { version = "0.13.3", registry = "strafesnet" }
|
||||||
roblox_emulator = { path = "../roblox_emulator", registry = "strafesnet" }
|
roblox_emulator = { path = "../roblox_emulator", registry = "strafesnet" }
|
||||||
|
6
lib/rbx_loader/src/directories.rs
Normal file
6
lib/rbx_loader/src/directories.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// TODO: make a directories structure like strafe client
|
||||||
|
struct Directories{
|
||||||
|
textures:PathBuf,
|
||||||
|
meshes:PathBuf,
|
||||||
|
unions:PathBuf,
|
||||||
|
}
|
@ -3,6 +3,7 @@ use rbx_dom_weak::WeakDom;
|
|||||||
|
|
||||||
mod rbx;
|
mod rbx;
|
||||||
mod mesh;
|
mod mesh;
|
||||||
|
mod union;
|
||||||
mod primitives;
|
mod primitives;
|
||||||
|
|
||||||
pub mod data{
|
pub mod data{
|
||||||
|
4
lib/rbx_loader/src/loader.rs
Normal file
4
lib/rbx_loader/src/loader.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// TODO: move code from deferred_loader to here
|
||||||
|
// use generics to specify a hashable type for the acquire_X function signature
|
||||||
|
// use impls/traits instead of passing around functions
|
||||||
|
// part of the goob remains in deferred loader, the common bits between both
|
@ -1,7 +1,7 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use rbx_mesh::mesh::{Vertex2, Vertex2Truncated};
|
use rbx_mesh::mesh::{Vertex2,Vertex2Truncated};
|
||||||
use strafesnet_common::{integer::vec3,model::{self, ColorId, IndexedVertex, NormalId, PolygonGroup, PolygonList, PositionId, TextureCoordinateId, VertexId}};
|
use strafesnet_common::{integer::vec3,model::{self,ColorId,IndexedVertex,NormalId,PolygonGroup,PolygonList,PositionId,RenderConfigId,TextureCoordinateId,VertexId}};
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -205,7 +205,13 @@ pub fn convert(roblox_mesh_bytes:crate::data::RobloxMeshBytes)->Result<model::Me
|
|||||||
unique_vertices,
|
unique_vertices,
|
||||||
polygon_groups,
|
polygon_groups,
|
||||||
//these should probably be moved to the model...
|
//these should probably be moved to the model...
|
||||||
graphics_groups:Vec::new(),
|
//but what if models want to use the same texture
|
||||||
|
graphics_groups:vec![model::IndexedGraphicsGroup{
|
||||||
|
render:RenderConfigId::new(0),
|
||||||
|
//the lowest lod is highest quality
|
||||||
|
groups:vec![model::PolygonGroupId::new(0)]
|
||||||
|
}],
|
||||||
|
//disable physics
|
||||||
physics_groups:Vec::new(),
|
physics_groups:Vec::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -403,13 +403,94 @@ enum RobloxBasePartDescription{
|
|||||||
Wedge(RobloxWedgeDescription),
|
Wedge(RobloxWedgeDescription),
|
||||||
CornerWedge(RobloxCornerWedgeDescription),
|
CornerWedge(RobloxCornerWedgeDescription),
|
||||||
}
|
}
|
||||||
|
fn get_texture_description<AcquireRenderConfigId>(
|
||||||
|
temp_objects:&mut Vec<rbx_dom_weak::types::Ref>,
|
||||||
|
acquire_render_config_id:&mut AcquireRenderConfigId,
|
||||||
|
dom:&rbx_dom_weak::WeakDom,
|
||||||
|
object:&rbx_dom_weak::Instance,
|
||||||
|
size:&rbx_dom_weak::types::Vector3,
|
||||||
|
)->RobloxPartDescription
|
||||||
|
where
|
||||||
|
AcquireRenderConfigId:FnMut(Option<&str>)->model::RenderConfigId,
|
||||||
|
{
|
||||||
|
//use the biggest one and cut it down later...
|
||||||
|
let mut part_texture_description:RobloxPartDescription=[None,None,None,None,None,None];
|
||||||
|
temp_objects.clear();
|
||||||
|
recursive_collect_superclass(temp_objects,&dom,object,"Decal");
|
||||||
|
for &mut decal_ref in temp_objects{
|
||||||
|
if let Some(decal)=dom.get_by_ref(decal_ref){
|
||||||
|
if let (
|
||||||
|
Some(rbx_dom_weak::types::Variant::Content(content)),
|
||||||
|
Some(rbx_dom_weak::types::Variant::Enum(normalid)),
|
||||||
|
Some(rbx_dom_weak::types::Variant::Color3(decal_color3)),
|
||||||
|
Some(rbx_dom_weak::types::Variant::Float32(decal_transparency)),
|
||||||
|
) = (
|
||||||
|
decal.properties.get("Texture"),
|
||||||
|
decal.properties.get("Face"),
|
||||||
|
decal.properties.get("Color3"),
|
||||||
|
decal.properties.get("Transparency"),
|
||||||
|
) {
|
||||||
|
let render_id=acquire_render_config_id(Some(content.as_ref()));
|
||||||
|
let normal_id=normalid.to_u32();
|
||||||
|
if normal_id<6{
|
||||||
|
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)),
|
||||||
|
) = (
|
||||||
|
decal.properties.get("OffsetStudsU"),
|
||||||
|
decal.properties.get("OffsetStudsV"),
|
||||||
|
decal.properties.get("StudsPerTileU"),
|
||||||
|
decal.properties.get("StudsPerTileV"),
|
||||||
|
)
|
||||||
|
{
|
||||||
|
let (size_u,size_v)=match normal_id{
|
||||||
|
0=>(size.z,size.y),//right
|
||||||
|
1=>(size.x,size.z),//top
|
||||||
|
2=>(size.x,size.y),//back
|
||||||
|
3=>(size.z,size.y),//left
|
||||||
|
4=>(size.x,size.z),//bottom
|
||||||
|
5=>(size.x,size.y),//front
|
||||||
|
_=>unreachable!(),
|
||||||
|
};
|
||||||
|
(
|
||||||
|
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),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}else{
|
||||||
|
(glam::Vec4::ONE,RobloxTextureTransform::default())
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
(glam::Vec4::ONE,RobloxTextureTransform::default())
|
||||||
|
};
|
||||||
|
part_texture_description[normal_id as usize]=Some(RobloxFaceTextureDescription{
|
||||||
|
render:render_id,
|
||||||
|
color:roblox_texture_color,
|
||||||
|
transform:roblox_texture_transform,
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
println!("NormalId={} is invalid",normal_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
part_texture_description
|
||||||
|
}
|
||||||
enum Shape{
|
enum Shape{
|
||||||
Primitive(primitives::Primitives),
|
Primitive(primitives::Primitives),
|
||||||
MeshPart,
|
MeshPart,
|
||||||
|
PhysicsData,
|
||||||
}
|
}
|
||||||
enum MeshAvailability{
|
enum MeshAvailability<'a>{
|
||||||
Immediate,
|
Immediate,
|
||||||
Deferred(RenderConfigId),
|
DeferredMesh(RenderConfigId),
|
||||||
|
DeferredUnion(RobloxPartDescription,UnionDeferredAttributes<'a>),
|
||||||
}
|
}
|
||||||
struct DeferredModelDeferredAttributes{
|
struct DeferredModelDeferredAttributes{
|
||||||
render:RenderConfigId,
|
render:RenderConfigId,
|
||||||
@ -421,6 +502,17 @@ struct ModelDeferredAttributes{
|
|||||||
color:model::Color4,//transparency is in here
|
color:model::Color4,//transparency is in here
|
||||||
transform:Planar64Affine3,
|
transform:Planar64Affine3,
|
||||||
}
|
}
|
||||||
|
struct DeferredUnionDeferredAttributes<'a>{
|
||||||
|
render:RobloxPartDescription,
|
||||||
|
model:ModelDeferredAttributes,
|
||||||
|
union:UnionDeferredAttributes<'a>,
|
||||||
|
}
|
||||||
|
#[derive(Hash)]
|
||||||
|
struct UnionDeferredAttributes<'a>{
|
||||||
|
asset_id:Option<&'a str>,
|
||||||
|
mesh_data:Option<&'a [u8]>,
|
||||||
|
physics_data:Option<&'a [u8]>,
|
||||||
|
}
|
||||||
struct ModelOwnedAttributes{
|
struct ModelOwnedAttributes{
|
||||||
mesh:model::MeshId,
|
mesh:model::MeshId,
|
||||||
attributes:attr::CollisionAttributes,
|
attributes:attr::CollisionAttributes,
|
||||||
@ -432,16 +524,17 @@ struct GetAttributesArgs{
|
|||||||
can_collide:bool,
|
can_collide:bool,
|
||||||
velocity:Planar64Vec3,
|
velocity:Planar64Vec3,
|
||||||
}
|
}
|
||||||
pub fn convert<AcquireRenderConfigId,AcquireMeshId>(
|
pub fn convert<'a,AcquireRenderConfigId,AcquireMeshId>(
|
||||||
dom:&rbx_dom_weak::WeakDom,
|
dom:&'a rbx_dom_weak::WeakDom,
|
||||||
mut acquire_render_config_id:AcquireRenderConfigId,
|
mut acquire_render_config_id:AcquireRenderConfigId,
|
||||||
mut acquire_mesh_id:AcquireMeshId,
|
mut acquire_mesh_id:AcquireMeshId,
|
||||||
)->PartialMap1
|
)->PartialMap1<'a>
|
||||||
where
|
where
|
||||||
AcquireRenderConfigId:FnMut(Option<&str>)->model::RenderConfigId,
|
AcquireRenderConfigId:FnMut(Option<&str>)->model::RenderConfigId,
|
||||||
AcquireMeshId:FnMut(&str)->model::MeshId,
|
AcquireMeshId:FnMut(&str)->model::MeshId,
|
||||||
{
|
{
|
||||||
|
|
||||||
|
let mut deferred_unions_deferred_attributes=Vec::new();
|
||||||
let mut deferred_models_deferred_attributes=Vec::new();
|
let mut deferred_models_deferred_attributes=Vec::new();
|
||||||
let mut primitive_models_deferred_attributes=Vec::new();
|
let mut primitive_models_deferred_attributes=Vec::new();
|
||||||
let mut primitive_meshes=Vec::new();
|
let mut primitive_meshes=Vec::new();
|
||||||
@ -471,7 +564,7 @@ where
|
|||||||
object.properties.get("CanCollide"),
|
object.properties.get("CanCollide"),
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
let model_transform=planar64_affine3_from_roblox(cf,size);
|
let mut model_transform=planar64_affine3_from_roblox(cf,size);
|
||||||
|
|
||||||
if model_transform.matrix3.det().is_zero(){
|
if model_transform.matrix3.det().is_zero(){
|
||||||
let mut parent_ref=object.parent();
|
let mut parent_ref=object.parent();
|
||||||
@ -503,6 +596,7 @@ where
|
|||||||
"WedgePart"=>Shape::Primitive(primitives::Primitives::Wedge),
|
"WedgePart"=>Shape::Primitive(primitives::Primitives::Wedge),
|
||||||
"CornerWedgePart"=>Shape::Primitive(primitives::Primitives::CornerWedge),
|
"CornerWedgePart"=>Shape::Primitive(primitives::Primitives::CornerWedge),
|
||||||
"MeshPart"=>Shape::MeshPart,
|
"MeshPart"=>Shape::MeshPart,
|
||||||
|
"UnionOperation"=>Shape::PhysicsData,
|
||||||
_=>{
|
_=>{
|
||||||
println!("Unsupported BasePart ClassName={}; defaulting to cube",object.class);
|
println!("Unsupported BasePart ClassName={}; defaulting to cube",object.class);
|
||||||
Shape::Primitive(primitives::Primitives::Cube)
|
Shape::Primitive(primitives::Primitives::Cube)
|
||||||
@ -511,74 +605,8 @@ where
|
|||||||
|
|
||||||
let (availability,mesh_id)=match shape{
|
let (availability,mesh_id)=match shape{
|
||||||
Shape::Primitive(primitive_shape)=>{
|
Shape::Primitive(primitive_shape)=>{
|
||||||
//TODO: TAB TAB
|
//TODO: TAB TAB
|
||||||
//use the biggest one and cut it down later...
|
let part_texture_description=get_texture_description(&mut temp_objects,&mut acquire_render_config_id,dom,object,size);
|
||||||
let mut part_texture_description:RobloxPartDescription=[None,None,None,None,None,None];
|
|
||||||
temp_objects.clear();
|
|
||||||
recursive_collect_superclass(&mut temp_objects, &dom, object,"Decal");
|
|
||||||
for &decal_ref in &temp_objects{
|
|
||||||
if let Some(decal)=dom.get_by_ref(decal_ref){
|
|
||||||
if let (
|
|
||||||
Some(rbx_dom_weak::types::Variant::Content(content)),
|
|
||||||
Some(rbx_dom_weak::types::Variant::Enum(normalid)),
|
|
||||||
Some(rbx_dom_weak::types::Variant::Color3(decal_color3)),
|
|
||||||
Some(rbx_dom_weak::types::Variant::Float32(decal_transparency)),
|
|
||||||
) = (
|
|
||||||
decal.properties.get("Texture"),
|
|
||||||
decal.properties.get("Face"),
|
|
||||||
decal.properties.get("Color3"),
|
|
||||||
decal.properties.get("Transparency"),
|
|
||||||
) {
|
|
||||||
let render_id=acquire_render_config_id(Some(content.as_ref()));
|
|
||||||
let normal_id=normalid.to_u32();
|
|
||||||
if normal_id<6{
|
|
||||||
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)),
|
|
||||||
) = (
|
|
||||||
decal.properties.get("OffsetStudsU"),
|
|
||||||
decal.properties.get("OffsetStudsV"),
|
|
||||||
decal.properties.get("StudsPerTileU"),
|
|
||||||
decal.properties.get("StudsPerTileV"),
|
|
||||||
)
|
|
||||||
{
|
|
||||||
let (size_u,size_v)=match normal_id{
|
|
||||||
0=>(size.z,size.y),//right
|
|
||||||
1=>(size.x,size.z),//top
|
|
||||||
2=>(size.x,size.y),//back
|
|
||||||
3=>(size.z,size.y),//left
|
|
||||||
4=>(size.x,size.z),//bottom
|
|
||||||
5=>(size.x,size.y),//front
|
|
||||||
_=>unreachable!(),
|
|
||||||
};
|
|
||||||
(
|
|
||||||
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),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}else{
|
|
||||||
(glam::Vec4::ONE,RobloxTextureTransform::default())
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
(glam::Vec4::ONE,RobloxTextureTransform::default())
|
|
||||||
};
|
|
||||||
part_texture_description[normal_id as usize]=Some(RobloxFaceTextureDescription{
|
|
||||||
render:render_id,
|
|
||||||
color:roblox_texture_color,
|
|
||||||
transform:roblox_texture_transform,
|
|
||||||
});
|
|
||||||
}else{
|
|
||||||
println!("NormalId={} unsupported for shape={:?}",normal_id,primitive_shape);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//obscure rust syntax "slice pattern"
|
//obscure rust syntax "slice pattern"
|
||||||
let [
|
let [
|
||||||
f0,//Cube::Right
|
f0,//Cube::Right
|
||||||
@ -691,12 +719,45 @@ where
|
|||||||
object.properties.get("TextureID"),
|
object.properties.get("TextureID"),
|
||||||
){
|
){
|
||||||
(
|
(
|
||||||
MeshAvailability::Deferred(acquire_render_config_id(Some(texture_asset_id.as_ref()))),
|
MeshAvailability::DeferredMesh(acquire_render_config_id(Some(texture_asset_id.as_ref()))),
|
||||||
acquire_mesh_id(mesh_asset_id.as_ref()),
|
acquire_mesh_id(mesh_asset_id.as_ref()),
|
||||||
)
|
)
|
||||||
}else{
|
}else{
|
||||||
panic!("Mesh has no Mesh or Texture");
|
panic!("Mesh has no Mesh or Texture");
|
||||||
},
|
},
|
||||||
|
Shape::PhysicsData=>{
|
||||||
|
//The union mesh is sized already
|
||||||
|
model_transform=planar64_affine3_from_roblox(cf,&rbx_dom_weak::types::Vector3{x:2.0,y:2.0,z:2.0});
|
||||||
|
|
||||||
|
let mut asset_id=None;
|
||||||
|
let mut mesh_data=None;
|
||||||
|
let mut physics_data=None;
|
||||||
|
if let Some(rbx_dom_weak::types::Variant::Content(content))=object.properties.get("AssetId"){
|
||||||
|
let value:&str=content.as_ref();
|
||||||
|
if !value.is_empty(){
|
||||||
|
asset_id=Some(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(rbx_dom_weak::types::Variant::BinaryString(data))=object.properties.get("MeshData"){
|
||||||
|
let value:&[u8]=data.as_ref();
|
||||||
|
if !value.is_empty(){
|
||||||
|
mesh_data=Some(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(rbx_dom_weak::types::Variant::BinaryString(data))=object.properties.get("PhysicsData"){
|
||||||
|
let value:&[u8]=data.as_ref();
|
||||||
|
if !value.is_empty(){
|
||||||
|
physics_data=Some(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let part_texture_description=get_texture_description(&mut temp_objects,&mut acquire_render_config_id,dom,object,size);
|
||||||
|
let union_deferred_attributes=UnionDeferredAttributes{
|
||||||
|
asset_id,
|
||||||
|
mesh_data,
|
||||||
|
physics_data,
|
||||||
|
};
|
||||||
|
(MeshAvailability::DeferredUnion(part_texture_description,union_deferred_attributes),mesh_id)
|
||||||
|
},
|
||||||
};
|
};
|
||||||
let model_deferred_attributes=ModelDeferredAttributes{
|
let model_deferred_attributes=ModelDeferredAttributes{
|
||||||
mesh:mesh_id,
|
mesh:mesh_id,
|
||||||
@ -710,10 +771,15 @@ where
|
|||||||
};
|
};
|
||||||
match availability{
|
match availability{
|
||||||
MeshAvailability::Immediate=>primitive_models_deferred_attributes.push(model_deferred_attributes),
|
MeshAvailability::Immediate=>primitive_models_deferred_attributes.push(model_deferred_attributes),
|
||||||
MeshAvailability::Deferred(render)=>deferred_models_deferred_attributes.push(DeferredModelDeferredAttributes{
|
MeshAvailability::DeferredMesh(render)=>deferred_models_deferred_attributes.push(DeferredModelDeferredAttributes{
|
||||||
render,
|
render,
|
||||||
model:model_deferred_attributes
|
model:model_deferred_attributes
|
||||||
}),
|
}),
|
||||||
|
MeshAvailability::DeferredUnion(part_texture_description,union_deferred_attributes)=>deferred_unions_deferred_attributes.push(DeferredUnionDeferredAttributes{
|
||||||
|
render:part_texture_description,
|
||||||
|
model:model_deferred_attributes,
|
||||||
|
union:union_deferred_attributes,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -728,10 +794,11 @@ struct MeshWithAabb{
|
|||||||
mesh:model::Mesh,
|
mesh:model::Mesh,
|
||||||
aabb:strafesnet_common::aabb::Aabb,
|
aabb:strafesnet_common::aabb::Aabb,
|
||||||
}
|
}
|
||||||
pub struct PartialMap1{
|
pub struct PartialMap1<'a>{
|
||||||
primitive_meshes:Vec<model::Mesh>,
|
primitive_meshes:Vec<model::Mesh>,
|
||||||
primitive_models_deferred_attributes:Vec<ModelDeferredAttributes>,
|
primitive_models_deferred_attributes:Vec<ModelDeferredAttributes>,
|
||||||
deferred_models_deferred_attributes:Vec<DeferredModelDeferredAttributes>,
|
deferred_models_deferred_attributes:Vec<DeferredModelDeferredAttributes>,
|
||||||
|
deferred_union_deferred_attributes:Vec<DeferredModelDeferredAttributes>,
|
||||||
}
|
}
|
||||||
impl PartialMap1{
|
impl PartialMap1{
|
||||||
pub fn add_meshpart_meshes_and_calculate_attributes(
|
pub fn add_meshpart_meshes_and_calculate_attributes(
|
||||||
@ -776,12 +843,10 @@ impl PartialMap1{
|
|||||||
.entry(render).or_insert_with(||{
|
.entry(render).or_insert_with(||{
|
||||||
let mesh_id=model::MeshId::new(self.primitive_meshes.len() as u32);
|
let mesh_id=model::MeshId::new(self.primitive_meshes.len() as u32);
|
||||||
let mut mesh_clone=mesh_with_aabb.mesh.clone();
|
let mut mesh_clone=mesh_with_aabb.mesh.clone();
|
||||||
//add a render group lool
|
//set the render group lool
|
||||||
mesh_clone.graphics_groups.push(model::IndexedGraphicsGroup{
|
if let Some(graphics_group)=mesh_clone.graphics_groups.first_mut(){
|
||||||
render,
|
graphics_group.render=render;
|
||||||
//the lowest lod is highest quality
|
}
|
||||||
groups:vec![model::PolygonGroupId::new(0)]
|
|
||||||
});
|
|
||||||
self.primitive_meshes.push(mesh_clone);
|
self.primitive_meshes.push(mesh_clone);
|
||||||
mesh_id
|
mesh_id
|
||||||
}),
|
}),
|
||||||
|
144
lib/rbx_loader/src/union.rs
Normal file
144
lib/rbx_loader/src/union.rs
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use strafesnet_common::model::{self, ColorId, IndexedVertex, NormalId, PolygonGroup, PolygonGroupId, PolygonList, PositionId, RenderConfigId, TextureCoordinateId, VertexId};
|
||||||
|
use strafesnet_common::integer::vec3;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error{
|
||||||
|
Block,
|
||||||
|
NotSupposedToHappen,
|
||||||
|
MissingVertexId(u32),
|
||||||
|
Planar64Vec3(strafesnet_common::integer::Planar64TryFromFloatError),
|
||||||
|
RobloxPhysicsData(rbx_mesh::physics_data::Error),
|
||||||
|
RobloxMeshData(rbx_mesh::mesh_data::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{}
|
||||||
|
pub fn convert(roblox_physics_data:&[u8],roblox_mesh_data:&[u8])->Result<model::Mesh,Error>{
|
||||||
|
match (roblox_physics_data,roblox_mesh_data){
|
||||||
|
(b"",b"")=>return Err(Error::Block),
|
||||||
|
(b"",_)
|
||||||
|
|(_,b"")=>return Err(Error::NotSupposedToHappen),
|
||||||
|
_=>(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// graphical
|
||||||
|
let mesh_data=rbx_mesh::read_mesh_data_versioned(
|
||||||
|
std::io::Cursor::new(roblox_mesh_data)
|
||||||
|
).map_err(Error::RobloxMeshData)?;
|
||||||
|
let graphics_mesh=match mesh_data{
|
||||||
|
rbx_mesh::mesh_data::CSGPHS::CSGK(csgk)=>return Err(Error::NotSupposedToHappen),
|
||||||
|
rbx_mesh::mesh_data::CSGPHS::CSGPHS2(mesh_data2)=>mesh_data2.mesh,
|
||||||
|
rbx_mesh::mesh_data::CSGPHS::CSGPHS4(mesh_data4)=>mesh_data4.mesh,
|
||||||
|
};
|
||||||
|
|
||||||
|
// physical
|
||||||
|
let physics_data=rbx_mesh::read_physics_data(
|
||||||
|
std::io::Cursor::new(roblox_physics_data)
|
||||||
|
).map_err(Error::RobloxPhysicsData)?;
|
||||||
|
let physics_convex_meshes=match physics_data{
|
||||||
|
rbx_mesh::physics_data::PhysicsData::CSGK(_)
|
||||||
|
// have not seen this format in practice
|
||||||
|
|rbx_mesh::physics_data::PhysicsData::CSGPHS(rbx_mesh::physics_data::CSGPHS::Block)
|
||||||
|
=>return Err(Error::NotSupposedToHappen),
|
||||||
|
rbx_mesh::physics_data::PhysicsData::CSGPHS(rbx_mesh::physics_data::CSGPHS::Meshes3(meshes))
|
||||||
|
|rbx_mesh::physics_data::PhysicsData::CSGPHS(rbx_mesh::physics_data::CSGPHS::Meshes5(meshes))
|
||||||
|
=>meshes.meshes,
|
||||||
|
rbx_mesh::physics_data::PhysicsData::CSGPHS(rbx_mesh::physics_data::CSGPHS::PhysicsInfoMesh(pim))
|
||||||
|
=>vec![pim.mesh],
|
||||||
|
};
|
||||||
|
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 acquire_pos_id=|pos|{
|
||||||
|
let p=vec3::try_from_f32_array(pos).map_err(Error::Planar64Vec3)?;
|
||||||
|
Ok(*pos_id_from.entry(p).or_insert_with(||{
|
||||||
|
let pos_id=PositionId::new(unique_pos.len() as u32);
|
||||||
|
unique_pos.push(p);
|
||||||
|
pos_id
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
let mut acquire_tex_id=|tex|{
|
||||||
|
let h=bytemuck::cast::<[f32;2],[u32;2]>(tex);
|
||||||
|
*tex_id_from.entry(h).or_insert_with(||{
|
||||||
|
let tex_id=TextureCoordinateId::new(unique_tex.len() as u32);
|
||||||
|
unique_tex.push(glam::Vec2::from_array(tex));
|
||||||
|
tex_id
|
||||||
|
})
|
||||||
|
};
|
||||||
|
let mut acquire_normal_id=|normal|{
|
||||||
|
let n=vec3::try_from_f32_array(normal).map_err(Error::Planar64Vec3)?;
|
||||||
|
Ok(*normal_id_from.entry(n).or_insert_with(||{
|
||||||
|
let normal_id=NormalId::new(unique_normal.len() as u32);
|
||||||
|
unique_normal.push(n);
|
||||||
|
normal_id
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
let mut acquire_color_id=|color|{
|
||||||
|
let h=bytemuck::cast::<[f32;4],[u32;4]>(color);
|
||||||
|
*color_id_from.entry(h).or_insert_with(||{
|
||||||
|
let color_id=ColorId::new(unique_color.len() as u32);
|
||||||
|
unique_color.push(glam::Vec4::from_array(color));
|
||||||
|
color_id
|
||||||
|
})
|
||||||
|
};
|
||||||
|
let mut acquire_vertex_id=|vertex:IndexedVertex|{
|
||||||
|
*vertex_id_from.entry(vertex.clone()).or_insert_with(||{
|
||||||
|
let vertex_id=VertexId::new(unique_vertices.len() as u32);
|
||||||
|
unique_vertices.push(vertex);
|
||||||
|
vertex_id
|
||||||
|
})
|
||||||
|
};
|
||||||
|
let color=acquire_color_id([1.0f32;4]);
|
||||||
|
let tex=acquire_tex_id([0.0f32;2]);
|
||||||
|
let polygon_groups:Vec<PolygonGroup>=physics_convex_meshes.into_iter().map(|mesh|{
|
||||||
|
Ok(PolygonGroup::PolygonList(PolygonList::new(mesh.faces.into_iter().map(|[vertex_id0,vertex_id1,vertex_id2]|{
|
||||||
|
let v0=mesh.vertices.get(vertex_id0.0 as usize).ok_or(Error::MissingVertexId(vertex_id0.0))?;
|
||||||
|
let v1=mesh.vertices.get(vertex_id1.0 as usize).ok_or(Error::MissingVertexId(vertex_id1.0))?;
|
||||||
|
let v2=mesh.vertices.get(vertex_id2.0 as usize).ok_or(Error::MissingVertexId(vertex_id2.0))?;
|
||||||
|
let vertex_norm=(glam::Vec3::from_slice(v1)-glam::Vec3::from_slice(v0))
|
||||||
|
.cross(glam::Vec3::from_slice(v2)-glam::Vec3::from_slice(v0)).to_array();
|
||||||
|
let mut ingest_vertex_id=|&vertex_pos:&[f32;3]|Ok(acquire_vertex_id(IndexedVertex{
|
||||||
|
pos:acquire_pos_id(vertex_pos)?,
|
||||||
|
tex,
|
||||||
|
normal:acquire_normal_id(vertex_norm)?,
|
||||||
|
color,
|
||||||
|
}));
|
||||||
|
Ok(vec![
|
||||||
|
ingest_vertex_id(v0)?,
|
||||||
|
ingest_vertex_id(v1)?,
|
||||||
|
ingest_vertex_id(v2)?,
|
||||||
|
])
|
||||||
|
}).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{
|
||||||
|
groups:vec![PolygonGroupId::new(id as u32)]
|
||||||
|
}).collect();
|
||||||
|
Ok(model::Mesh{
|
||||||
|
unique_pos,
|
||||||
|
unique_normal,
|
||||||
|
unique_tex,
|
||||||
|
unique_color,
|
||||||
|
unique_vertices,
|
||||||
|
polygon_groups,
|
||||||
|
graphics_groups,
|
||||||
|
physics_groups,
|
||||||
|
})
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user