unique model per face texture algorithm
This commit is contained in:
parent
b404908a55
commit
f492a09377
@ -49,6 +49,52 @@ impl std::str::FromStr for RobloxAssetId {
|
|||||||
Err(RobloxAssetIdParseErr)
|
Err(RobloxAssetIdParseErr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[derive(Clone,Copy,PartialEq)]
|
||||||
|
struct RobloxTextureTransform{
|
||||||
|
offset_u:f32,
|
||||||
|
offset_v:f32,
|
||||||
|
scale_u:f32,
|
||||||
|
scale_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}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Hash)]
|
||||||
|
struct PartFaceTextureDescription{
|
||||||
|
texture:u32,
|
||||||
|
transform:RobloxTextureTransform,
|
||||||
|
}
|
||||||
|
type PartTextureDescription=[Option<PartFaceTextureDescription>;6];
|
||||||
|
#[derive(Hash,Eq,PartialEq)]
|
||||||
|
struct RobloxUnitCubeGenerationData{
|
||||||
|
texture:Option<u32>,
|
||||||
|
faces:[Option<RobloxTextureTransform>;6],
|
||||||
|
}
|
||||||
|
impl std::default::Default for RobloxUnitCubeGenerationData{
|
||||||
|
fn default() -> Self {
|
||||||
|
Self{
|
||||||
|
texture:None,
|
||||||
|
faces:[Some(RobloxTextureTransform::default());6],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl RobloxUnitCubeGenerationData{
|
||||||
|
fn empty() -> Self {
|
||||||
|
Self{
|
||||||
|
texture:None,
|
||||||
|
faces:[None,None,None,None,None,None],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn generate_modeldatas_roblox(dom:rbx_dom_weak::WeakDom) -> Result<(Vec<ModelData>,Vec<String>,glam::Vec3), Box<dyn std::error::Error>>{
|
pub fn generate_modeldatas_roblox(dom:rbx_dom_weak::WeakDom) -> Result<(Vec<ModelData>,Vec<String>,glam::Vec3), Box<dyn std::error::Error>>{
|
||||||
@ -56,14 +102,14 @@ pub fn generate_modeldatas_roblox(dom:rbx_dom_weak::WeakDom) -> Result<(Vec<Mode
|
|||||||
let mut spawn_point=glam::Vec3::ZERO;
|
let mut spawn_point=glam::Vec3::ZERO;
|
||||||
|
|
||||||
//TODO: generate unit Block, Wedge, etc. after based on part shape lists
|
//TODO: generate unit Block, Wedge, etc. after based on part shape lists
|
||||||
let mut modeldatas=crate::model::generate_modeldatas(primitives::the_unit_cube_lol(),ModelData::COLOR_FLOATS_WHITE);
|
let mut modeldatas=Vec::new();
|
||||||
let unit_cube_modeldata=modeldatas[0].clone();
|
|
||||||
|
|
||||||
let mut texture_id_from_asset_id=std::collections::HashMap::<u64,u32>::new();
|
let mut texture_id_from_asset_id=std::collections::HashMap::<u64,u32>::new();
|
||||||
let mut asset_id_from_texture_id=Vec::new();
|
let mut asset_id_from_texture_id=Vec::new();
|
||||||
|
|
||||||
let mut object_refs = std::vec::Vec::new();
|
let mut object_refs=Vec::new();
|
||||||
let mut temp_objects = std::vec::Vec::new();
|
let mut temp_objects=Vec::new();
|
||||||
|
let mut model_id_from_ucgd=std::collections::HashMap::<RobloxUnitCubeGenerationData,usize>::new();
|
||||||
recursive_collect_superclass(&mut object_refs, &dom, dom.root(),"BasePart");
|
recursive_collect_superclass(&mut object_refs, &dom, dom.root(),"BasePart");
|
||||||
for object_ref in object_refs {
|
for object_ref in object_refs {
|
||||||
if let Some(object)=dom.get_by_ref(object_ref){
|
if let Some(object)=dom.get_by_ref(object_ref){
|
||||||
@ -104,59 +150,117 @@ pub fn generate_modeldatas_roblox(dom:rbx_dom_weak::WeakDom) -> Result<(Vec<Mode
|
|||||||
temp_objects.clear();
|
temp_objects.clear();
|
||||||
recursive_collect_superclass(&mut temp_objects, &dom, object,"Decal");
|
recursive_collect_superclass(&mut temp_objects, &dom, object,"Decal");
|
||||||
|
|
||||||
let mut texture_transform=glam::Affine2::IDENTITY;
|
let mut part_texture_description:PartTextureDescription=[None,None,None,None,None,None];
|
||||||
let mut i_can_only_load_one_texture_per_model=None;
|
|
||||||
for &decal_ref in &temp_objects{
|
for &decal_ref in &temp_objects{
|
||||||
if let Some(decal)=dom.get_by_ref(decal_ref){
|
if let Some(decal)=dom.get_by_ref(decal_ref){
|
||||||
if let Some(rbx_dom_weak::types::Variant::Content(content)) = decal.properties.get("Texture") {
|
if let (
|
||||||
if decal.class=="Texture"{
|
Some(rbx_dom_weak::types::Variant::Content(content)),
|
||||||
//generate tranform
|
Some(rbx_dom_weak::types::Variant::Enum(normalid)),
|
||||||
if let (
|
) = (
|
||||||
Some(rbx_dom_weak::types::Variant::Float32(ox)),
|
decal.properties.get("Texture"),
|
||||||
Some(rbx_dom_weak::types::Variant::Float32(oy)),
|
decal.properties.get("Face"),
|
||||||
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"),
|
|
||||||
)
|
|
||||||
{
|
|
||||||
//pretend we don't need to know the face
|
|
||||||
texture_transform=glam::Affine2::from_translation(
|
|
||||||
glam::vec2(*ox/size.x,*oy/size.y)
|
|
||||||
)
|
|
||||||
*glam::Affine2::from_scale(
|
|
||||||
glam::vec2(*sx/size.x,*sy/size.y)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Ok(asset_id)=content.clone().into_string().parse::<RobloxAssetId>(){
|
if let Ok(asset_id)=content.clone().into_string().parse::<RobloxAssetId>(){
|
||||||
if let Some(&texture_id)=texture_id_from_asset_id.get(&asset_id.0){
|
let texture_id=if let Some(&texture_id)=texture_id_from_asset_id.get(&asset_id.0){
|
||||||
i_can_only_load_one_texture_per_model=Some(texture_id);
|
texture_id
|
||||||
}else{
|
}else{
|
||||||
let texture_id=asset_id_from_texture_id.len();
|
let texture_id=asset_id_from_texture_id.len() as u32;
|
||||||
texture_id_from_asset_id.insert(asset_id.0,texture_id as u32);
|
texture_id_from_asset_id.insert(asset_id.0,texture_id);
|
||||||
asset_id_from_texture_id.push(asset_id.0);
|
asset_id_from_texture_id.push(asset_id.0);
|
||||||
//make new model
|
texture_id
|
||||||
let mut unit_cube_texture=unit_cube_modeldata.clone();
|
};
|
||||||
unit_cube_texture.texture=Some(texture_id as u32);
|
let face=normalid.to_u32();
|
||||||
modeldatas.push(unit_cube_texture);
|
if face<6{
|
||||||
|
let mut roblox_texture_transform=RobloxTextureTransform::default();
|
||||||
|
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"),
|
||||||
|
)
|
||||||
|
{
|
||||||
|
//pretend we don't need to know the face
|
||||||
|
roblox_texture_transform=RobloxTextureTransform{
|
||||||
|
offset_u:*ox/size.x,offset_v:*oy/size.y,
|
||||||
|
scale_u:*sx/size.x,scale_v:*sy/size.y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//I can alos put the color into here and generate the vertices with the color
|
||||||
|
part_texture_description[face as usize]=Some(PartFaceTextureDescription{
|
||||||
|
texture:texture_id,
|
||||||
|
transform:roblox_texture_transform,
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
println!("goofy ahh roblox gave NormalId {}", face);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let model_instance=ModelInstance {
|
let mut unit_cube_generation_data_list=Vec::new();
|
||||||
model_transform,
|
let mut unit_cube_from_texture_id=std::collections::HashMap::<u32,usize>::new();
|
||||||
color: glam::vec4(color3.r as f32/255f32, color3.g as f32/255f32, color3.b as f32/255f32, 1.0-*transparency),
|
//use part_texture_description to extract unique texture faces
|
||||||
};
|
let mut add_negative_cube=false;
|
||||||
match i_can_only_load_one_texture_per_model{
|
let mut negative_cube=RobloxUnitCubeGenerationData::empty();
|
||||||
//push to existing texture model
|
for (i,maybe_part_face) in part_texture_description.iter().enumerate(){
|
||||||
Some(texture_id)=>modeldatas[(texture_id+1) as usize].instances.push(model_instance),
|
if let Some(part_face)=maybe_part_face{
|
||||||
//push instance to big unit cube in the sky
|
let unit_cube_id=if let Some(&unit_cube_id)=unit_cube_from_texture_id.get(&part_face.texture){
|
||||||
None=>modeldatas[0].instances.push(model_instance),
|
unit_cube_id
|
||||||
|
}else{
|
||||||
|
let unit_cube_id=unit_cube_generation_data_list.len();
|
||||||
|
unit_cube_generation_data_list.push(RobloxUnitCubeGenerationData::empty());
|
||||||
|
unit_cube_from_texture_id.insert(part_face.texture,unit_cube_id);
|
||||||
|
unit_cube_generation_data_list[unit_cube_id].texture=Some(part_face.texture);
|
||||||
|
unit_cube_id
|
||||||
|
};
|
||||||
|
unit_cube_generation_data_list[unit_cube_id].faces[i]=Some(part_face.transform);
|
||||||
|
}else{
|
||||||
|
add_negative_cube=true;
|
||||||
|
negative_cube.faces[i]=Some(RobloxTextureTransform::default());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//must add the rest of the cube to complete the faces!
|
||||||
|
if add_negative_cube{
|
||||||
|
unit_cube_generation_data_list.push(negative_cube);
|
||||||
|
}
|
||||||
|
for roblox_unit_cube_generation_data in unit_cube_generation_data_list.drain(..){
|
||||||
|
//make new model if unit cube has not been crated before
|
||||||
|
let model_id=if let Some(&model_id)=model_id_from_ucgd.get(&roblox_unit_cube_generation_data){
|
||||||
|
//push to existing texture model
|
||||||
|
model_id
|
||||||
|
}else{
|
||||||
|
let unit_cube_generation_data=roblox_unit_cube_generation_data.faces.map(|face|{
|
||||||
|
match face{
|
||||||
|
Some(roblox_texture_transform)=>Some(
|
||||||
|
glam::Affine2::from_translation(
|
||||||
|
glam::vec2(roblox_texture_transform.offset_u,roblox_texture_transform.offset_v)
|
||||||
|
)
|
||||||
|
*glam::Affine2::from_scale(
|
||||||
|
glam::vec2(roblox_texture_transform.scale_u,roblox_texture_transform.scale_v)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
None=>None,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let mut new_modeldatas=crate::model::generate_modeldatas(primitives::generate_partial_unit_cube(unit_cube_generation_data),ModelData::COLOR_FLOATS_WHITE);
|
||||||
|
new_modeldatas[0].texture=roblox_unit_cube_generation_data.texture;
|
||||||
|
let model_id=modeldatas.len();
|
||||||
|
modeldatas.append(&mut new_modeldatas);
|
||||||
|
model_id_from_ucgd.insert(roblox_unit_cube_generation_data,model_id);
|
||||||
|
model_id
|
||||||
|
};
|
||||||
|
modeldatas[model_id].instances.push(ModelInstance {
|
||||||
|
model_transform,
|
||||||
|
color: glam::vec4(color3.r as f32/255f32, color3.g as f32/255f32, color3.b as f32/255f32, 1.0-*transparency),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,58 @@
|
|||||||
pub fn the_unit_cube_lol() -> obj::ObjData{
|
pub fn the_unit_cube_lol() -> obj::ObjData{
|
||||||
|
generate_partial_unit_cube([Some(glam::Affine2::IDENTITY);6])
|
||||||
|
}
|
||||||
|
pub fn generate_partial_unit_cube(face_transforms:[Option<glam::Affine2>;6])->obj::ObjData{
|
||||||
|
let default_polys=vec![
|
||||||
|
// right (1, 0, 0)
|
||||||
|
obj::SimplePolygon(vec![
|
||||||
|
obj::IndexTuple(6,Some(0),Some(0)),
|
||||||
|
obj::IndexTuple(5,Some(1),Some(0)),
|
||||||
|
obj::IndexTuple(2,Some(2),Some(0)),
|
||||||
|
obj::IndexTuple(1,Some(3),Some(0)),
|
||||||
|
]),
|
||||||
|
// top (0, 1, 0)
|
||||||
|
obj::SimplePolygon(vec![
|
||||||
|
obj::IndexTuple(5,Some(1),Some(1)),
|
||||||
|
obj::IndexTuple(4,Some(0),Some(1)),
|
||||||
|
obj::IndexTuple(3,Some(3),Some(1)),
|
||||||
|
obj::IndexTuple(2,Some(2),Some(1)),
|
||||||
|
]),
|
||||||
|
// back (0, 0, 1)
|
||||||
|
obj::SimplePolygon(vec![
|
||||||
|
obj::IndexTuple(0,Some(0),Some(2)),
|
||||||
|
obj::IndexTuple(1,Some(1),Some(2)),
|
||||||
|
obj::IndexTuple(2,Some(2),Some(2)),
|
||||||
|
obj::IndexTuple(3,Some(3),Some(2)),
|
||||||
|
]),
|
||||||
|
// left (-1, 0, 0)
|
||||||
|
obj::SimplePolygon(vec![
|
||||||
|
obj::IndexTuple(0,Some(0),Some(3)),
|
||||||
|
obj::IndexTuple(3,Some(1),Some(3)),
|
||||||
|
obj::IndexTuple(4,Some(2),Some(3)),
|
||||||
|
obj::IndexTuple(7,Some(3),Some(3)),
|
||||||
|
]),
|
||||||
|
// bottom (0,-1, 0)
|
||||||
|
obj::SimplePolygon(vec![
|
||||||
|
obj::IndexTuple(1,Some(1),Some(4)),
|
||||||
|
obj::IndexTuple(0,Some(0),Some(4)),
|
||||||
|
obj::IndexTuple(7,Some(3),Some(4)),
|
||||||
|
obj::IndexTuple(6,Some(2),Some(4)),
|
||||||
|
]),
|
||||||
|
// front (0, 0,-1)
|
||||||
|
obj::SimplePolygon(vec![
|
||||||
|
obj::IndexTuple(4,Some(0),Some(5)),
|
||||||
|
obj::IndexTuple(5,Some(1),Some(5)),
|
||||||
|
obj::IndexTuple(6,Some(2),Some(5)),
|
||||||
|
obj::IndexTuple(7,Some(3),Some(5)),
|
||||||
|
]),
|
||||||
|
];
|
||||||
|
//generate transformed vertices
|
||||||
|
let mut generated_polys=Vec::new();
|
||||||
|
for (i,maybe_transform) in face_transforms.iter().enumerate(){
|
||||||
|
if let Some(transform)=maybe_transform{
|
||||||
|
generated_polys.push(default_polys[i].clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
obj::ObjData{
|
obj::ObjData{
|
||||||
position: vec![
|
position: vec![
|
||||||
[-1.,-1., 1.],//left bottom back
|
[-1.,-1., 1.],//left bottom back
|
||||||
@ -12,12 +66,12 @@ pub fn the_unit_cube_lol() -> obj::ObjData{
|
|||||||
],
|
],
|
||||||
texture: vec![[0.0,0.0],[1.0,0.0],[1.0,1.0],[0.0,1.0]],
|
texture: vec![[0.0,0.0],[1.0,0.0],[1.0,1.0],[0.0,1.0]],
|
||||||
normal: vec![
|
normal: vec![
|
||||||
[1.,0.,0.],//AabbFace::Right
|
[ 1., 0., 0.],//AabbFace::Right
|
||||||
[0.,1.,0.],//AabbFace::Top
|
[ 0., 1., 0.],//AabbFace::Top
|
||||||
[0.,0.,1.],//AabbFace::Back
|
[ 0., 0., 1.],//AabbFace::Back
|
||||||
[-1.,0.,0.],//AabbFace::Left
|
[-1., 0., 0.],//AabbFace::Left
|
||||||
[0.,-1.,0.],//AabbFace::Bottom
|
[ 0.,-1., 0.],//AabbFace::Bottom
|
||||||
[0.,0.,-1.],//AabbFace::Front
|
[ 0., 0.,-1.],//AabbFace::Front
|
||||||
],
|
],
|
||||||
objects: vec![obj::Object{
|
objects: vec![obj::Object{
|
||||||
name: "Unit Cube".to_owned(),
|
name: "Unit Cube".to_owned(),
|
||||||
@ -25,50 +79,7 @@ pub fn the_unit_cube_lol() -> obj::ObjData{
|
|||||||
name: "Cube Vertices".to_owned(),
|
name: "Cube Vertices".to_owned(),
|
||||||
index: 0,
|
index: 0,
|
||||||
material: None,
|
material: None,
|
||||||
polys: vec![
|
polys: generated_polys,
|
||||||
// back (0, 0, 1)
|
|
||||||
obj::SimplePolygon(vec![
|
|
||||||
obj::IndexTuple(0,Some(0),Some(2)),
|
|
||||||
obj::IndexTuple(1,Some(1),Some(2)),
|
|
||||||
obj::IndexTuple(2,Some(2),Some(2)),
|
|
||||||
obj::IndexTuple(3,Some(3),Some(2)),
|
|
||||||
]),
|
|
||||||
// front (0, 0,-1)
|
|
||||||
obj::SimplePolygon(vec![
|
|
||||||
obj::IndexTuple(4,Some(0),Some(5)),
|
|
||||||
obj::IndexTuple(5,Some(1),Some(5)),
|
|
||||||
obj::IndexTuple(6,Some(2),Some(5)),
|
|
||||||
obj::IndexTuple(7,Some(3),Some(5)),
|
|
||||||
]),
|
|
||||||
// right (1, 0, 0)
|
|
||||||
obj::SimplePolygon(vec![
|
|
||||||
obj::IndexTuple(6,Some(0),Some(0)),
|
|
||||||
obj::IndexTuple(5,Some(1),Some(0)),
|
|
||||||
obj::IndexTuple(2,Some(2),Some(0)),
|
|
||||||
obj::IndexTuple(1,Some(3),Some(0)),
|
|
||||||
]),
|
|
||||||
// left (-1, 0, 0)
|
|
||||||
obj::SimplePolygon(vec![
|
|
||||||
obj::IndexTuple(0,Some(0),Some(3)),
|
|
||||||
obj::IndexTuple(3,Some(1),Some(3)),
|
|
||||||
obj::IndexTuple(4,Some(2),Some(3)),
|
|
||||||
obj::IndexTuple(7,Some(3),Some(3)),
|
|
||||||
]),
|
|
||||||
// top (0, 1, 0)
|
|
||||||
obj::SimplePolygon(vec![
|
|
||||||
obj::IndexTuple(5,Some(1),Some(1)),
|
|
||||||
obj::IndexTuple(4,Some(0),Some(1)),
|
|
||||||
obj::IndexTuple(3,Some(3),Some(1)),
|
|
||||||
obj::IndexTuple(2,Some(2),Some(1)),
|
|
||||||
]),
|
|
||||||
// bottom (0,-1, 0)
|
|
||||||
obj::SimplePolygon(vec![
|
|
||||||
obj::IndexTuple(1,Some(1),Some(4)),
|
|
||||||
obj::IndexTuple(0,Some(0),Some(4)),
|
|
||||||
obj::IndexTuple(7,Some(3),Some(4)),
|
|
||||||
obj::IndexTuple(6,Some(2),Some(4)),
|
|
||||||
]),
|
|
||||||
],
|
|
||||||
}]
|
}]
|
||||||
}],
|
}],
|
||||||
material_libs: Vec::new(),
|
material_libs: Vec::new(),
|
||||||
|
Loading…
Reference in New Issue
Block a user