diff --git a/rust/src/unity/asset_file.rs b/rust/src/unity/asset_file.rs index 536fc2f4c..5285474f9 100644 --- a/rust/src/unity/asset_file.rs +++ b/rust/src/unity/asset_file.rs @@ -111,7 +111,7 @@ mod tests { use std::str::FromStr; use crate::unity::types::common::UnityVersion; - use crate::unity::types::wasm::{GameObject, Mesh, MeshFilter, MeshRenderer, Transform}; + use crate::unity::types::wasm::{GameObject, Texture2D, Mesh, MeshFilter, MeshRenderer, Transform, Material}; use crate::unity::types::serialized_file::ObjectInfo; use super::*; @@ -121,7 +121,7 @@ mod tests { #[test] fn test() { let mut base_path = PathBuf::from_str("C:\\Users\\ifnsp\\dev\\noclip.website\\data\\AShortHike").unwrap(); - let data = std::fs::read(&base_path.join("level2")).unwrap(); + let data = std::fs::read(&base_path.join("resources.assets")).unwrap(); let version = UnityVersion::V2021_3_27f1; let mut asset_file = AssetFile::initialize_with_header_chunk(&data).unwrap(); dbg!(&asset_file.header); @@ -144,54 +144,32 @@ mod tests { ext_files.push(ext_file); } - let mut objects = HashMap::new(); - let mut object_infos = HashMap::new(); for obj in asset_file.get_objects() { - if !matches!(obj.class_id, ClassID::GameObject) { - object_infos.insert(obj.file_id, obj); - continue; - } let data = &data[obj.byte_start as usize..obj.byte_start as usize + obj.byte_size]; - let game_object = GameObject::create(version, data).unwrap(); - objects.insert(obj.file_id, game_object); - object_infos.insert(obj.file_id, obj); - } - - let mut successes = HashSet::new(); - for obj in objects.values() { - for component_ptr in &obj.components { - if component_ptr.file_index != 0 { - dbg!(component_ptr); - continue; - } - let obj = object_infos.get(&component_ptr.path_id).unwrap(); - if successes.contains(&obj.file_id) { - continue; - } - let bigdata = &data; - let data = &data[obj.byte_start as usize..obj.byte_start as usize + obj.byte_size]; - - match obj.class_id { - ClassID::Transform => {Transform::create(version, data).unwrap();}, - ClassID::RectTransform => {Transform::create(version, data).unwrap();}, - ClassID::MeshFilter => { - let filter = MeshFilter::create(version, data).unwrap(); - if filter.mesh.path_id == 0 || filter.mesh.file_index != 0 || successes.contains(&filter.mesh.path_id) { - continue; - } - let obj = object_infos.get(&filter.mesh.path_id).unwrap(); - let data = &bigdata[obj.byte_start as usize..obj.byte_start as usize + obj.byte_size]; - - println!("reading mesh {}", obj.file_id); - let mut mesh = Mesh::create(version, data).unwrap(); - successes.insert(obj.file_id); - mesh.submeshes.clear(); - mesh.index_buffer.clear(); - }, - ClassID::MeshRenderer => {MeshRenderer::create(version, data).unwrap();}, - _ => {}, - } - successes.insert(obj.file_id); + match obj.class_id { + ClassID::Transform => { + Transform::create(version, data).unwrap(); + }, + ClassID::RectTransform => { + Transform::create(version, data).unwrap(); + }, + ClassID::MeshFilter => { + MeshFilter::create(version, data).unwrap(); + }, + ClassID::Mesh => { + Mesh::create(version, data).unwrap(); + }, + ClassID::MeshRenderer => { + MeshRenderer::create(version, data).unwrap(); + }, + ClassID::Material => { + Material::create(version, data).unwrap(); + }, + ClassID::Texture2D => { + println!("parsing Texture2D {}", obj.file_id); + Texture2D::create(version, data).unwrap(); + }, + _ => {}, } } } diff --git a/rust/src/unity/types/binary.rs b/rust/src/unity/types/binary.rs index 35cb99e62..39914c781 100644 --- a/rust/src/unity/types/binary.rs +++ b/rust/src/unity/types/binary.rs @@ -32,20 +32,41 @@ pub struct Transform { } #[derive(DekuRead, Clone, Debug)] -#[deku(ctx = "_version: UnityVersion")] +#[deku(ctx = "version: UnityVersion")] pub struct Material { pub name: CharArray, + #[deku(count = "(4 - deku::byte_offset % 4) % 4")] _alignment0: Vec, pub shader: PPtr<()>, - pub shader_keywords: CharArray, + #[deku(cond = "version < UnityVersion::V2021_3_27f1")] + pub shader_keywords: Option, + #[deku(count = "(4 - deku::byte_offset % 4) % 4")] _alignment1: Vec, + #[deku(cond = "version >= UnityVersion::V2021_3_27f1")] + pub valid_keywords: Option>, + #[deku(count = "(4 - deku::byte_offset % 4) % 4")] _alignment2: Vec, + #[deku(cond = "version >= UnityVersion::V2021_3_27f1")] + pub invalid_keywords: Option>, + #[deku(count = "(4 - deku::byte_offset % 4) % 4")] _alignment3: Vec, pub lightmap_flags: u32, pub enable_instancing_variants: u8, pub double_sided_gi: u8, + #[deku(count = "(4 - deku::byte_offset % 4) % 4")] _alignment4: Vec, pub custom_render_queue: u32, pub string_tag_map: Map, pub disabled_shader_passes: UnityArray, + #[deku(count = "(4 - deku::byte_offset % 4) % 4")] _alignment5: Vec, pub tex_envs: Map, + #[deku(cond = "version >= UnityVersion::V2021_3_27f1")] + pub ints: Option>, pub floats: Map, pub colors: Map, + #[deku(cond = "version >= UnityVersion::V2020_3_16f1")] + pub build_texture_stacks: Option>, +} + +#[derive(DekuRead, Clone, Debug)] +pub struct BuildTextureStackReference { + pub group_name: CharArray, + pub item_name: CharArray, } #[derive(DekuRead, Clone, Debug)] @@ -70,13 +91,13 @@ pub struct MeshRenderer { pub cast_shadows: u8, pub receive_shadows: u8, pub dynamic_occludee: u8, - #[deku(cond = "version > UnityVersion::V2021_3_27f1")] + #[deku(cond = "version >= UnityVersion::V2021_3_27f1")] pub static_shadow_caster: Option, pub motion_vectors: u8, pub light_probe_usage: u8, pub reflection_probe_usage: u8, pub ray_tracing_mode: u8, - #[deku(cond = "version > UnityVersion::V2021_3_27f1")] + #[deku(cond = "version >= UnityVersion::V2020_3_16f1")] pub ray_trace_procedural: Option, #[deku(count = "(4 - deku::byte_offset % 4) % 4")] _alignment: Vec, pub rendering_layer_mask: u32, @@ -94,7 +115,7 @@ pub struct MeshRenderer { pub sorting_layer: i16, pub sorting_order: i16, pub additional_vertex_streams: PPtr, - #[deku(cond = "version > UnityVersion::V2021_3_27f1")] + #[deku(cond = "version >= UnityVersion::V2021_3_27f1")] pub enlighten_vertex_streams: Option>, } @@ -214,10 +235,10 @@ pub struct ChannelInfo { pub stream: u8, pub offset: u8, pub format: VertexFormat, - #[deku(bits = "3")] - pub dimension: u8, #[deku(bits = "1", pad_bits_after = "4")] pub instance_data: u8, + #[deku(bits = "3")] + pub dimension: u8, } #[derive(DekuRead, Clone, Debug)] @@ -280,28 +301,54 @@ pub struct StaticBatchInfo { #[deku(ctx = "version: UnityVersion")] pub struct Texture2D { pub name: CharArray, + #[deku(count = "(4 - deku::byte_offset % 4) % 4")] _alignment0: Vec, pub forced_fallback_format: i32, pub downscale_fallback: u8, + pub is_alpha_channel_optional: u8, + #[deku(count = "(4 - deku::byte_offset % 4) % 4")] _alignment1: Vec, pub width: i32, pub height: i32, - pub complete_image_size: i32, + pub complete_image_size: u32, + #[deku(cond = "version >= UnityVersion::V2020_3_16f1")] + pub mips_stripped: Option, pub texture_format: TextureFormat, pub mip_count: i32, - pub is_readable: u8, - pub ignore_master_texture_limit: u8, - pub is_preprocessed: u8, - pub streaming_mipmaps: u8, + #[deku(ctx = "version")] + pub settings: TextureBooleanSettings, pub streaming_mipmaps_priority: i32, pub image_count: i32, pub texture_dimension: i32, pub texture_settings: GLTextureSettings, pub lightmap_format: i32, pub color_space: ColorSpace, + #[deku(cond = "version >= UnityVersion::V2020_3_16f1")] + pub platform_blob: UnityArray, + #[deku(count = "(4 - deku::byte_offset % 4) % 4")] _alignment2: Vec, pub data: UnityArray, + #[deku(count = "(4 - deku::byte_offset % 4) % 4")] _alignment3: Vec, #[deku(ctx = "version")] pub streaming_info: StreamingInfo, } +#[derive(DekuRead, Debug, Clone)] +#[deku(ctx = "version: UnityVersion", id = "version")] +pub enum TextureBooleanSettings { + #[deku(id_pat = "UnityVersion::V2019_4_39f1")] + V2019 { + is_readable: u8, + ignore_master_texture_limit: u8, + is_preprocessed: u8, + streaming_mipmaps: u8, + }, + #[deku(id_pat = "_")] + V2020 { + is_readable: u8, + is_preprocessed: u8, + ignore_master_texture_limit: u8, + streaming_mipmaps: u8, + } +} + #[derive(DekuRead, Clone, Debug)] pub struct GLTextureSettings { pub filter_mode: TextureFilterMode, diff --git a/rust/src/unity/types/common.rs b/rust/src/unity/types/common.rs index bd69d83a8..266b3e284 100644 --- a/rust/src/unity/types/common.rs +++ b/rust/src/unity/types/common.rs @@ -14,7 +14,7 @@ pub enum UnityVersion { V2021_3_27f1, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct UnityArray { pub values: Vec, } @@ -100,7 +100,7 @@ impl From> for HashMap } } -#[derive(DekuRead, Clone)] +#[derive(DekuRead, Clone, Default)] pub struct CharArray { count: u32, #[deku(count = "*count")] diff --git a/rust/src/unity/types/wasm.rs b/rust/src/unity/types/wasm.rs index bf74822a2..80186c7f0 100644 --- a/rust/src/unity/types/wasm.rs +++ b/rust/src/unity/types/wasm.rs @@ -69,12 +69,13 @@ pub struct Transform { } #[wasm_bindgen(js_name = "UnityMaterial", getter_with_clone)] -#[derive(FromStructPerField)] -#[from(binary::Material)] +#[derive(Debug, Clone)] pub struct Material { pub name: String, pub shader: WasmFriendlyPPtr, - pub shader_keywords: String, + pub shader_keywords: Option, + pub valid_keywords: Option>, + pub invalid_keywords: Option>, pub lightmap_flags: u32, pub enable_instancing_variants: u8, pub double_sided_gi: u8, @@ -86,6 +87,36 @@ pub struct Material { colors: HashMap, } +impl From for Material { + fn from(value: binary::Material) -> Self { + Self { + name: value.name.into(), + shader: value.shader.into(), + shader_keywords: match value.shader_keywords { + Some(v) => Some(v.into()), + None => None, + }, + valid_keywords: match value.valid_keywords { + Some(v) => Some(v.into()), + None => None, + }, + invalid_keywords: match value.invalid_keywords { + Some(v) => Some(v.into()), + None => None, + }, + lightmap_flags: value.lightmap_flags.into(), + enable_instancing_variants: value.enable_instancing_variants.into(), + double_sided_gi: value.double_sided_gi.into(), + custom_render_queue: value.custom_render_queue.into(), + string_tag_map: value.string_tag_map.into(), + disabled_shader_passes: value.disabled_shader_passes.into(), + tex_envs: value.tex_envs.into(), + floats: value.floats.into(), + colors: value.colors.into(), + } + } +} + #[wasm_bindgen(js_class = "UnityMaterial")] impl Material { pub fn get_tex_env_keys(&self) -> Vec { @@ -385,15 +416,13 @@ pub struct StreamingInfo { } #[wasm_bindgen(js_name = "UnityTexture2D", getter_with_clone)] -#[derive(Clone, Debug, FromStructPerField)] -#[from(binary::Texture2D)] pub struct Texture2D { pub name: String, pub forced_fallback_format: i32, pub downscale_fallback: u8, pub width: i32, pub height: i32, - pub complete_image_size: i32, + pub complete_image_size: u32, pub texture_format: TextureFormat, pub mip_count: i32, pub is_readable: u8, @@ -410,6 +439,41 @@ pub struct Texture2D { pub streaming_info: StreamingInfo, } +impl From for Texture2D { + fn from(value: binary::Texture2D) -> Self { + let s = value.settings; + let (is_readable, + ignore_master_texture_limit, + is_preprocessed, + streaming_mipmaps) = match s { + binary::TextureBooleanSettings::V2019 { is_readable: a, ignore_master_texture_limit: b, is_preprocessed: c, streaming_mipmaps: d } => (a, b, c, d), + binary::TextureBooleanSettings::V2020 { is_readable: a, ignore_master_texture_limit: b, is_preprocessed: c, streaming_mipmaps: d } => (a, b, c, d), + }; + Self { + name: value.name.into(), + forced_fallback_format: value.forced_fallback_format.into(), + downscale_fallback: value.downscale_fallback.into(), + width: value.width.into(), + height: value.height.into(), + complete_image_size: value.complete_image_size.into(), + texture_format: value.texture_format.into(), + mip_count: value.mip_count.into(), + is_readable, + ignore_master_texture_limit, + is_preprocessed, + streaming_mipmaps, + streaming_mipmaps_priority: value.streaming_mipmaps_priority.into(), + image_count: value.image_count.into(), + texture_dimension: value.texture_dimension.into(), + texture_settings: value.texture_settings.into(), + lightmap_format: value.lightmap_format.into(), + color_space: value.color_space.into(), + data: value.data.into(), + streaming_info: value.streaming_info.into(), + } + } +} + #[wasm_bindgen(js_name = "UnityGLTextureSettings", getter_with_clone)] #[derive(Clone, Debug, FromStructPerField)] #[from(binary::GLTextureSettings)] diff --git a/src/AShortHike/Scenes.ts b/src/AShortHike/Scenes.ts index a84b07152..3d9af7784 100644 --- a/src/AShortHike/Scenes.ts +++ b/src/AShortHike/Scenes.ts @@ -202,7 +202,6 @@ class TerrainMaterial extends UnityMaterialInstance { class AShortHikeMaterialFactory extends UnityMaterialFactory { public createMaterialInstance(runtime: UnityRuntime, materialData: UnityMaterialData): UnityMaterialInstance { - debugger; // TODO(jstpierre): Pull out serialized shader data if (materialData.name.includes('_Splat3')) return new TerrainMaterial(runtime, materialData); @@ -229,7 +228,7 @@ class UnityRenderer implements Viewer.SceneGfx { const template = this.renderHelper.pushTemplateRenderInst(); template.setBindingLayouts(bindingLayouts); - let offs = template.allocateUniformBuffer(0, 32); + let offs = template.allocateUniformBuffer(0, 16); const mapped = template.mapUniformBufferF32(0); offs += fillMatrix4x4(mapped, offs, viewerInput.camera.clipFromWorldMatrix); diff --git a/src/Common/Unity/AssetManager.ts b/src/Common/Unity/AssetManager.ts index 26c8d43f9..5fcb00e70 100644 --- a/src/Common/Unity/AssetManager.ts +++ b/src/Common/Unity/AssetManager.ts @@ -300,7 +300,7 @@ export class AssetFile { this.dataCache.set(pathID, v); return v; }).catch(e => { - console.error(`failed to fetch ${pathID}, ${e}`); + console.error(`failed to fetch ${this.path}: ${pathID}, ${e}`); throw e; }); }); @@ -739,7 +739,7 @@ export class UnityMaterialData { public fillTexEnvScaleBias(d: Float32Array, offs: number, name: string): number { const texture = this.texturesByName.get(name); if (texture !== undefined) { - return fillVec4(d, texture.scale[0], texture.scale[1], texture.offset[0], texture.offset[1]); + return fillVec4(d, offs, texture.scale[0], texture.scale[1], texture.offset[0], texture.offset[1]); } else { return fillVec4(d, offs, 1, 1, 0, 0); } diff --git a/src/gfx/platform/GfxPlatformWebGL2.ts b/src/gfx/platform/GfxPlatformWebGL2.ts index a20c04d13..a08285284 100644 --- a/src/gfx/platform/GfxPlatformWebGL2.ts +++ b/src/gfx/platform/GfxPlatformWebGL2.ts @@ -907,7 +907,7 @@ class GfxImplP_GL implements GfxSwapChain, GfxDevice { if (initialData !== undefined) this.uploadBufferData(buffer, 0, initialData); - + return buffer; }