Skip to content

Commit

Permalink
kinda working!
Browse files Browse the repository at this point in the history
  • Loading branch information
wgreenberg committed Nov 12, 2024
1 parent a98ac86 commit 00dfacf
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 73 deletions.
74 changes: 26 additions & 48 deletions rust/src/unity/asset_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand All @@ -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);
Expand All @@ -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();
},
_ => {},
}
}
}
Expand Down
71 changes: 59 additions & 12 deletions rust/src/unity/types/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u8>,
pub shader: PPtr<()>,
pub shader_keywords: CharArray,
#[deku(cond = "version < UnityVersion::V2021_3_27f1")]
pub shader_keywords: Option<CharArray>,
#[deku(count = "(4 - deku::byte_offset % 4) % 4")] _alignment1: Vec<u8>,
#[deku(cond = "version >= UnityVersion::V2021_3_27f1")]
pub valid_keywords: Option<UnityArray<CharArray>>,
#[deku(count = "(4 - deku::byte_offset % 4) % 4")] _alignment2: Vec<u8>,
#[deku(cond = "version >= UnityVersion::V2021_3_27f1")]
pub invalid_keywords: Option<UnityArray<CharArray>>,
#[deku(count = "(4 - deku::byte_offset % 4) % 4")] _alignment3: Vec<u8>,
pub lightmap_flags: u32,
pub enable_instancing_variants: u8,
pub double_sided_gi: u8,
#[deku(count = "(4 - deku::byte_offset % 4) % 4")] _alignment4: Vec<u8>,
pub custom_render_queue: u32,
pub string_tag_map: Map<CharArray, CharArray>,
pub disabled_shader_passes: UnityArray<CharArray>,
#[deku(count = "(4 - deku::byte_offset % 4) % 4")] _alignment5: Vec<u8>,
pub tex_envs: Map<CharArray, TexEnv>,
#[deku(cond = "version >= UnityVersion::V2021_3_27f1")]
pub ints: Option<Map<CharArray, i32>>,
pub floats: Map<CharArray, f32>,
pub colors: Map<CharArray, ColorRGBA>,
#[deku(cond = "version >= UnityVersion::V2020_3_16f1")]
pub build_texture_stacks: Option<UnityArray<BuildTextureStackReference>>,
}

#[derive(DekuRead, Clone, Debug)]
pub struct BuildTextureStackReference {
pub group_name: CharArray,
pub item_name: CharArray,
}

#[derive(DekuRead, Clone, Debug)]
Expand All @@ -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<u8>,
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<u8>,
#[deku(count = "(4 - deku::byte_offset % 4) % 4")] _alignment: Vec<u8>,
pub rendering_layer_mask: u32,
Expand All @@ -94,7 +115,7 @@ pub struct MeshRenderer {
pub sorting_layer: i16,
pub sorting_order: i16,
pub additional_vertex_streams: PPtr<Mesh>,
#[deku(cond = "version > UnityVersion::V2021_3_27f1")]
#[deku(cond = "version >= UnityVersion::V2021_3_27f1")]
pub enlighten_vertex_streams: Option<PPtr<Mesh>>,
}

Expand Down Expand Up @@ -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)]
Expand Down Expand Up @@ -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<u8>,
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<u8>,
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<i32>,
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<u8>,
#[deku(count = "(4 - deku::byte_offset % 4) % 4")] _alignment2: Vec<u8>,
pub data: UnityArray<u8>,
#[deku(count = "(4 - deku::byte_offset % 4) % 4")] _alignment3: Vec<u8>,
#[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,
Expand Down
4 changes: 2 additions & 2 deletions rust/src/unity/types/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub enum UnityVersion {
V2021_3_27f1,
}

#[derive(Clone, Debug)]
#[derive(Clone, Debug, Default)]
pub struct UnityArray<T> {
pub values: Vec<T>,
}
Expand Down Expand Up @@ -100,7 +100,7 @@ impl<PreK, PreV, ResK, ResV> From<Map<PreK, PreV>> for HashMap<ResK, ResV>
}
}

#[derive(DekuRead, Clone)]
#[derive(DekuRead, Clone, Default)]
pub struct CharArray {
count: u32,
#[deku(count = "*count")]
Expand Down
76 changes: 70 additions & 6 deletions rust/src/unity/types/wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<String>,
pub valid_keywords: Option<Vec<String>>,
pub invalid_keywords: Option<Vec<String>>,
pub lightmap_flags: u32,
pub enable_instancing_variants: u8,
pub double_sided_gi: u8,
Expand All @@ -86,6 +87,36 @@ pub struct Material {
colors: HashMap<String, ColorRGBA>,
}

impl From<binary::Material> 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<String> {
Expand Down Expand Up @@ -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,
Expand All @@ -410,6 +439,41 @@ pub struct Texture2D {
pub streaming_info: StreamingInfo,
}

impl From<binary::Texture2D> 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)]
Expand Down
3 changes: 1 addition & 2 deletions src/AShortHike/Scenes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);

Expand Down
Loading

0 comments on commit 00dfacf

Please sign in to comment.