diff --git a/src/framework.rs b/src/framework.rs index b70479e..b471c22 100644 --- a/src/framework.rs +++ b/src/framework.rs @@ -53,7 +53,7 @@ pub trait Example: 'static + Sized { device: &wgpu::Device, queue: &wgpu::Queue, ); - fn update(&mut self, device: &wgpu::Device, event: WindowEvent); + fn update(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, event: WindowEvent); fn move_mouse(&mut self, delta: (f64,f64)); fn render( &mut self, @@ -369,7 +369,7 @@ fn start( println!("{:#?}", instance.generate_report()); } _ => { - example.update(&device,event); + example.update(&device,&queue,event); } }, event::Event::DeviceEvent { diff --git a/src/load_roblox.rs b/src/load_roblox.rs index 4b57736..f8cb69f 100644 --- a/src/load_roblox.rs +++ b/src/load_roblox.rs @@ -1,3 +1,9 @@ +use std::todo; + +use crate::model::{ModelData,ModelInstance}; + +use crate::primitives; + fn class_is_a(class: &str, superclass: &str) -> bool { if class==superclass { return true @@ -28,9 +34,105 @@ fn get_texture_refs(dom:&rbx_dom_weak::WeakDom) -> Vec //next class objects } -pub fn get_objects(dom:rbx_dom_weak::WeakDom, superclass: &str) -> Result, Box> { - let mut objects = std::vec::Vec::new(); - recursive_collect_superclass(&mut objects, &dom, dom.root(),superclass); - return Ok(objects) +struct RobloxAssetId(u64); +struct RobloxAssetIdParseErr; +impl std::str::FromStr for RobloxAssetId { + type Err=RobloxAssetIdParseErr; + fn from_str(s: &str) -> Result{ + let regman=regex::Regex::new(r"(\d+)$").unwrap(); + if let Some(captures) = regman.captures(s) { + if captures.len()==2{//captures[0] is all captures concatenated, and then each individual capture + if let Ok(id) = captures[0].parse::() { + return Ok(Self(id)); + } + } + } + Err(RobloxAssetIdParseErr) + } +} +pub fn generate_modeldatas_roblox(dom:&rbx_dom_weak::WeakDom) -> Result<(Vec,Vec), Box>{ + //ModelData includes texture dds + + //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 unit_cube_modeldata=modeldatas[0].clone(); + + let mut texture_id_from_asset_id=std::collections::HashMap::::new(); + let mut asset_id_from_texture_id=Vec::new(); + + let mut object_refs = std::vec::Vec::new(); + let mut temp_objects = std::vec::Vec::new(); + recursive_collect_superclass(&mut object_refs, &dom, dom.root(),"BasePart"); + for object_ref in object_refs { + if let Some(object)=dom.get_by_ref(object_ref){ + if let ( + Some(rbx_dom_weak::types::Variant::CFrame(cf)), + Some(rbx_dom_weak::types::Variant::Vector3(size)), + Some(rbx_dom_weak::types::Variant::Float32(transparency)), + Some(rbx_dom_weak::types::Variant::Color3uint8(color3)), + Some(rbx_dom_weak::types::Variant::Enum(shape)), + ) = ( + object.properties.get("CFrame"), + object.properties.get("Size"), + object.properties.get("Transparency"), + object.properties.get("Color"), + object.properties.get("Shape"),//this will also skip unions + ) + { + if *transparency==1.0||shape.to_u32()!=1 { + continue; + } + temp_objects.clear(); + recursive_collect_superclass(&mut temp_objects, &dom, object,"Decal"); + + let mut i_can_only_load_one_texture_per_model=None; + 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)) = decal.properties.get("Texture") { + if let Ok(asset_id)=content.clone().into_string().parse::(){ + 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); + }else{ + let texture_id=asset_id_from_texture_id.len(); + texture_id_from_asset_id.insert(asset_id.0,texture_id as u32); + asset_id_from_texture_id.push(asset_id.0); + //make new model + let mut unit_cube_texture=unit_cube_modeldata.clone(); + unit_cube_texture.texture=Some(texture_id as u32); + modeldatas.push(unit_cube_texture); + } + } + } + } + } + let model_instance=ModelInstance { + transform:glam::Mat4::from_translation( + glam::Vec3::new(cf.position.x,cf.position.y,cf.position.z) + ) + * glam::Mat4::from_mat3( + glam::Mat3::from_cols( + glam::Vec3::new(cf.orientation.x.x,cf.orientation.y.x,cf.orientation.z.x), + glam::Vec3::new(cf.orientation.x.y,cf.orientation.y.y,cf.orientation.z.y), + glam::Vec3::new(cf.orientation.x.z,cf.orientation.y.z,cf.orientation.z.z), + ), + ) + * glam::Mat4::from_scale( + glam::Vec3::new(size.x,size.y,size.z)/2.0 + ), + color: glam::vec4(color3.r as f32/255f32, color3.g as f32/255f32, color3.b as f32/255f32, 1.0-*transparency), + }; + match i_can_only_load_one_texture_per_model{ + //push to existing texture model + Some(texture_id)=>modeldatas[(texture_id+1) as usize].instances.push(model_instance), + //push instance to big unit cube in the sky + None=>modeldatas[0].instances.push(model_instance), + } + } + } + } + let texture_files:Result,_>=asset_id_from_texture_id.iter().map(|asset_id|{ + std::fs::File::open(std::path::Path::new(&format!("textures/{}.dds",asset_id))) + }).collect(); + Ok((modeldatas,texture_files?)) } diff --git a/src/main.rs b/src/main.rs index b6ca2c9..27a72e9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ mod body; mod model; mod zeroes; mod framework; +mod primitives; mod instruction; mod load_roblox; @@ -161,51 +162,6 @@ impl GraphicsData { depth_texture.create_view(&wgpu::TextureViewDescriptor::default()) } - fn generate_modeldatas_roblox(&self,dom:rbx_dom_weak::WeakDom) -> Vec{ - let mut modeldatas=generate_modeldatas(self.handy_unit_cube.clone(),ModelData::COLOR_FLOATS_WHITE); - match load_roblox::get_objects(dom, "BasePart") { - Ok(objects)=>{ - for object in objects.iter() { - if let ( - Some(rbx_dom_weak::types::Variant::CFrame(cf)), - Some(rbx_dom_weak::types::Variant::Vector3(size)), - Some(rbx_dom_weak::types::Variant::Float32(transparency)), - Some(rbx_dom_weak::types::Variant::Color3uint8(color3)), - Some(rbx_dom_weak::types::Variant::Enum(shape)), - ) = ( - object.properties.get("CFrame"), - object.properties.get("Size"), - object.properties.get("Transparency"), - object.properties.get("Color"), - object.properties.get("Shape"),//this will also skip unions - ) - { - if *transparency==1.0||shape.to_u32()!=1 { - continue; - } - modeldatas[0].instances.push(ModelInstance { - transform:glam::Mat4::from_translation( - glam::Vec3::new(cf.position.x,cf.position.y,cf.position.z) - ) - * glam::Mat4::from_mat3( - glam::Mat3::from_cols( - glam::Vec3::new(cf.orientation.x.x,cf.orientation.y.x,cf.orientation.z.x), - glam::Vec3::new(cf.orientation.x.y,cf.orientation.y.y,cf.orientation.z.y), - glam::Vec3::new(cf.orientation.x.z,cf.orientation.y.z,cf.orientation.z.z), - ), - ) - * glam::Mat4::from_scale( - glam::Vec3::new(size.x,size.y,size.z)/2.0 - ), - color: glam::vec4(color3.r as f32/255f32, color3.g as f32/255f32, color3.b as f32/255f32, 1.0-*transparency), - }) - } - } - }, - Err(e) => println!("lmao err {:?}", e), - } - modeldatas - } fn generate_model_physics(&mut self,modeldatas:&Vec){ self.physics.models.append(&mut modeldatas.iter().map(|m| //make aabb and run vertices to get realistic bounds @@ -213,7 +169,44 @@ impl GraphicsData { ).flatten().collect()); println!("Physics Objects: {}",self.physics.models.len()); } - fn generate_model_graphics(&mut self,device:&wgpu::Device,mut modeldatas:Vec){ + fn generate_model_graphics(&mut self,device:&wgpu::Device,queue:&wgpu::Queue,mut modeldatas:Vec,mut textures:Vec){ + //generate texture view per texture + let texture_views:Vec=textures.iter_mut().map(|mut t|{ + let image = ddsfile::Dds::read(&mut t).unwrap(); + + let size = wgpu::Extent3d { + width: image.get_width(), + height: image.get_height(), + depth_or_array_layers: 1, + }; + + let layer_size = wgpu::Extent3d { + depth_or_array_layers: 1, + ..size + }; + let max_mips = layer_size.max_mips(wgpu::TextureDimension::D2); + + let texture = device.create_texture_with_data( + queue, + &wgpu::TextureDescriptor { + size, + mip_level_count: max_mips, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Bc7RgbaUnorm, + usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, + label: Some("Squid Texture"), + view_formats: &[], + }, + &image.data, + ); + + texture.create_view(&wgpu::TextureViewDescriptor { + label: Some("Squid Texture View"), + dimension: Some(wgpu::TextureViewDimension::D2), + ..wgpu::TextureViewDescriptor::default() + }) + }).collect(); //drain the modeldata vec so entities can be /moved/ to models.entities let mut instance_count=0; self.models.reserve(modeldatas.len()); @@ -224,6 +217,10 @@ impl GraphicsData { contents: bytemuck::cast_slice(&model_uniforms), usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, }); + let texture_view=match modeldata.texture{ + Some(texture_id)=>&texture_views[texture_id as usize], + None=>&self.temp_squid_texture_view, + }; let model_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { layout: &self.bind_group_layouts.model, entries: &[ @@ -233,7 +230,7 @@ impl GraphicsData { }, wgpu::BindGroupEntry { binding: 1, - resource: wgpu::BindingResource::TextureView(&self.temp_squid_texture_view), + resource: wgpu::BindingResource::TextureView(texture_view), }, wgpu::BindGroupEntry { binding: 2, @@ -284,47 +281,6 @@ fn get_instances_buffer_data(instances:&Vec) -> Vec { raw } -fn generate_modeldatas(data:obj::ObjData,color:[f32;4]) -> Vec{ - let mut modeldatas=Vec::new(); - let mut vertices = Vec::new(); - let mut vertex_index = std::collections::HashMap::::new(); - for object in data.objects { - vertices.clear(); - vertex_index.clear(); - let mut entities = Vec::new(); - for group in object.groups { - let mut indices = Vec::new(); - for poly in group.polys { - for end_index in 2..poly.0.len() { - for &index in &[0, end_index - 1, end_index] { - let vert = poly.0[index]; - if let Some(&i)=vertex_index.get(&vert){ - indices.push(i); - }else{ - let i=vertices.len() as u16; - vertices.push(Vertex { - pos: data.position[vert.0], - texture: data.texture[vert.1.unwrap()], - normal: data.normal[vert.2.unwrap()], - color, - }); - vertex_index.insert(vert,i); - indices.push(i); - } - } - } - } - entities.push(indices); - } - modeldatas.push(ModelData { - instances: Vec::new(), - vertices:vertices.clone(), - entities, - }); - } - modeldatas -} - impl framework::Example for GraphicsData { fn optional_features() -> wgpu::Features { wgpu::Features::TEXTURE_COMPRESSION_ASTC @@ -340,85 +296,12 @@ impl framework::Example for GraphicsData { device: &wgpu::Device, queue: &wgpu::Queue, ) -> Self { - let unit_cube=obj::ObjData{ - position: vec![ - [-1.,-1., 1.],//left bottom back - [ 1.,-1., 1.],//right bottom back - [ 1., 1., 1.],//right top back - [-1., 1., 1.],//left top back - [-1., 1.,-1.],//left top front - [ 1., 1.,-1.],//right top front - [ 1.,-1.,-1.],//right bottom front - [-1.,-1.,-1.],//left bottom front - ], - texture: vec![[0.0,0.0],[1.0,0.0],[1.0,1.0],[0.0,1.0]], - normal: vec![ - [1.,0.,0.],//AabbFace::Right - [0.,1.,0.],//AabbFace::Top - [0.,0.,1.],//AabbFace::Back - [-1.,0.,0.],//AabbFace::Left - [0.,-1.,0.],//AabbFace::Bottom - [0.,0.,-1.],//AabbFace::Front - ], - objects: vec![obj::Object{ - name: "Unit Cube".to_owned(), - groups: vec![obj::Group{ - name: "Cube Vertices".to_owned(), - index: 0, - material: None, - polys: vec![ - // 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(), - }; + let unit_cube=primitives::the_unit_cube_lol(); let mut modeldatas = Vec::::new(); - modeldatas.append(&mut generate_modeldatas(obj::ObjData::load_buf(&include_bytes!("../models/teslacyberv3.0.obj")[..]).unwrap(),ModelData::COLOR_FLOATS_WHITE)); - modeldatas.append(&mut generate_modeldatas(obj::ObjData::load_buf(&include_bytes!("../models/suzanne.obj")[..]).unwrap(),ModelData::COLOR_FLOATS_WHITE)); - modeldatas.append(&mut generate_modeldatas(obj::ObjData::load_buf(&include_bytes!("../models/teapot.obj")[..]).unwrap(),ModelData::COLOR_FLOATS_WHITE)); - modeldatas.append(&mut generate_modeldatas(unit_cube.clone(),ModelData::COLOR_FLOATS_WHITE)); + modeldatas.append(&mut model::generate_modeldatas(obj::ObjData::load_buf(&include_bytes!("../models/teslacyberv3.0.obj")[..]).unwrap(),ModelData::COLOR_FLOATS_WHITE)); + modeldatas.append(&mut model::generate_modeldatas(obj::ObjData::load_buf(&include_bytes!("../models/suzanne.obj")[..]).unwrap(),ModelData::COLOR_FLOATS_WHITE)); + modeldatas.append(&mut model::generate_modeldatas(obj::ObjData::load_buf(&include_bytes!("../models/teapot.obj")[..]).unwrap(),ModelData::COLOR_FLOATS_WHITE)); + modeldatas.append(&mut model::generate_modeldatas(unit_cube.clone(),ModelData::COLOR_FLOATS_WHITE)); println!("models.len = {:?}", modeldatas.len()); modeldatas[0].instances.push(ModelInstance{ transform:glam::Mat4::from_translation(glam::vec3(10.,0.,-10.)), @@ -817,13 +700,13 @@ impl framework::Example for GraphicsData { }; graphics.generate_model_physics(&modeldatas); - graphics.generate_model_graphics(&device,modeldatas); + graphics.generate_model_graphics(&device,&queue,modeldatas,Vec::::new()); return graphics; } #[allow(clippy::single_match)] - fn update(&mut self, device: &wgpu::Device, event: winit::event::WindowEvent) { + fn update(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, event: winit::event::WindowEvent) { //nothing atm match event { winit::event::WindowEvent::DroppedFile(path) => { @@ -870,6 +753,13 @@ impl framework::Example for GraphicsData { }else{ println!("Failed ro read first 8 bytes and seek back to beginning of file."); } + //let input = std::io::BufReader::new(file); + //let (modeldatas,textures)=load_roblox::generate_modeldatas_roblox(input).unwrap(); + //if generate_modeldatas succeeds, clear the previous ones + //self.models.clear(); + //self.physics.models.clear(); + //self.generate_model_physics(&modeldatas); + //self.generate_model_graphics(device,queue,modeldatas,textures); }else{ println!("Could not open file"); } diff --git a/src/model.rs b/src/model.rs index e2ac139..99f4c0f 100644 --- a/src/model.rs +++ b/src/model.rs @@ -8,18 +8,63 @@ pub struct Vertex { pub color: [f32; 4], } +#[derive(Clone)] pub struct ModelInstance { pub transform: glam::Mat4, pub color: glam::Vec4, } +#[derive(Clone)] pub struct ModelData { pub instances: Vec, pub vertices: Vec, pub entities: Vec>, + pub texture: Option, } impl ModelData { pub const COLOR_FLOATS_WHITE: [f32;4] = [1.0,1.0,1.0,1.0]; pub const COLOR_VEC4_WHITE: glam::Vec4 = glam::vec4(1.0,1.0,1.0,1.0); +} + +pub fn generate_modeldatas(data:obj::ObjData,color:[f32;4]) -> Vec{ + let mut modeldatas=Vec::new(); + let mut vertices = Vec::new(); + let mut vertex_index = std::collections::HashMap::::new(); + for object in data.objects { + vertices.clear(); + vertex_index.clear(); + let mut entities = Vec::new(); + for group in object.groups { + let mut indices = Vec::new(); + for poly in group.polys { + for end_index in 2..poly.0.len() { + for &index in &[0, end_index - 1, end_index] { + let vert = poly.0[index]; + if let Some(&i)=vertex_index.get(&vert){ + indices.push(i); + }else{ + let i=vertices.len() as u16; + vertices.push(Vertex { + pos: data.position[vert.0], + texture: data.texture[vert.1.unwrap()], + normal: data.normal[vert.2.unwrap()], + color, + }); + vertex_index.insert(vert,i); + indices.push(i); + } + } + } + } + entities.push(indices); + } + modeldatas.push(ModelData { + instances: Vec::new(), + vertices:vertices.clone(), + entities, + texture: None, + }); + } + modeldatas } \ No newline at end of file diff --git a/src/primitives.rs b/src/primitives.rs new file mode 100644 index 0000000..a3c86d0 --- /dev/null +++ b/src/primitives.rs @@ -0,0 +1,76 @@ +pub fn the_unit_cube_lol() -> obj::ObjData{ + obj::ObjData{ + position: vec![ + [-1.,-1., 1.],//left bottom back + [ 1.,-1., 1.],//right bottom back + [ 1., 1., 1.],//right top back + [-1., 1., 1.],//left top back + [-1., 1.,-1.],//left top front + [ 1., 1.,-1.],//right top front + [ 1.,-1.,-1.],//right bottom front + [-1.,-1.,-1.],//left bottom front + ], + texture: vec![[0.0,0.0],[1.0,0.0],[1.0,1.0],[0.0,1.0]], + normal: vec![ + [1.,0.,0.],//AabbFace::Right + [0.,1.,0.],//AabbFace::Top + [0.,0.,1.],//AabbFace::Back + [-1.,0.,0.],//AabbFace::Left + [0.,-1.,0.],//AabbFace::Bottom + [0.,0.,-1.],//AabbFace::Front + ], + objects: vec![obj::Object{ + name: "Unit Cube".to_owned(), + groups: vec![obj::Group{ + name: "Cube Vertices".to_owned(), + index: 0, + material: None, + polys: vec![ + // 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(), + } +} \ No newline at end of file