use crate::proto::Mesh; use anyhow::Result; use glam::{Vec2, Vec3A, vec2, vec3a}; use weareshared::{packets::Resource, resources::MeshPart, store::ResourceStore}; pub fn convert_mesh( m: Mesh, store: &ResourceStore, normal_table: &[Vec3A], ) -> Result> { let index = decode_indices(&m.indices); let positions = decode_positions(m.vertices()); let texcoords = decode_texcoords(m.texture_coords()); let normals = decode_normals(m.normals(), normal_table); Ok(store.set(&MeshPart { index: Some(store.set(&index)?), va_position: Some(store.set(&positions)?), va_texcoord: texcoords.map(|x| store.set(&x)).transpose()?, va_normal: Some(store.set(&normals)?), g_double_sided: Some(()), ..Default::default() })?) } fn decode_texcoords(uv: &[u8]) -> Option> { if uv.is_empty() { return None; } let count = (uv.len() - 4) / 4; let u_mod = 1 + u16::from_le_bytes([uv[0], uv[1]]); let v_mod = 1 + u16::from_le_bytes([uv[2], uv[3]]); let uv = &uv[4..]; let (mut u, mut v) = (0u16, 0u16); let mut texcoords = Vec::new(); for i in 0..count { u = (u + (uv[count * 0 + i] as u16) + ((uv[count * 2 + i] as u16) << 8)) % u_mod; v = (v + (uv[count * 1 + i] as u16) + ((uv[count * 3 + i] as u16) << 8)) % v_mod; texcoords.push(vec2( u as f32 / u_mod as f32 + 0.5, v as f32 / v_mod as f32 + 0.5, )); } Some(texcoords) } fn decode_positions(vert: &[u8]) -> Vec { let mut positions = Vec::new(); let vertex_count = vert.len() / 3; let (mut x, mut y, mut z) = (0u8, 0u8, 0u8); for i in 0..vertex_count { x = x.wrapping_add(vert[vertex_count * 0 + i]); y = y.wrapping_add(vert[vertex_count * 1 + i]); z = z.wrapping_add(vert[vertex_count * 2 + i]); positions.push(vec3a(x as f32, y as f32, z as f32)); } positions } fn decode_indices(ind: &[i32]) -> Vec<[u32; 3]> { let mut index_strip = Vec::new(); let strip_len = ind[0]; let mut zeros = 0; for i in 0..strip_len { let val = ind[i as usize + 1]; index_strip.push((zeros - val) as u32); if val == 0 { zeros += 1; } } let mut index = Vec::new(); for i in 0..index_strip.len() - 2 { if i & 1 == 0 { index.push([index_strip[i + 0], index_strip[i + 1], index_strip[i + 2]]); } else { index.push([index_strip[i + 0], index_strip[i + 2], index_strip[i + 1]]); } } index } pub fn decode_normals(data: &[u8], normal_table: &[Vec3A]) -> Vec { let count = data.len() / 2; let mut normals = Vec::new(); for i in 0..count { let ind = data[i] as usize + ((data[i + count] as usize) << 8); normals.push(normal_table[ind]); } normals } pub fn decode_normal_table(data: &[u8]) -> Vec { // Pretty much taken straight from client/rocktree_decoder.h:111, no idea what f1 does. let f1 = |v: i32, l: i32| { if 4 >= l { (v << l) + (v & (1 << l) - 1) } else if 6 >= l { let r = 8 - l; (v << l) + (v << l >> r) + (v << l >> r >> r) + (v << l >> r >> r >> r) } else { -(v & 1) } }; let count = u16::from_le_bytes([data[0], data[1]]); let s = data[2] as i32; let data = &data[3..]; let mut output = Vec::new(); for i in 0..count { let mut a = f1(data[(count * 0 + i) as usize] as i32, s) as f32 / 255.; let f = f1(data[(count * 1 + i) as usize] as i32, s) as f32 / 255.; let mut b = a; let mut c = f; let mut g = c + b; let mut h = b - c; let mut sign = 1.; if !(0.5 <= g && 1.5 >= g && -0.5 <= h && 0.5 >= h) { sign = -1.; if 0.5 >= g { b = 0.5 - f; c = 0.5 - a; } else { if 1.5 <= g { b = 1.5 - f; c = 1.5 - a; } else { if -0.5 >= h { b = f - 0.5; c = a + 0.5; } else { b = f + 0.5; c = a - 0.5; } } } g = b + c; h = b - c; } let fmin = |a: f32, b: f32| a.min(b); a = fmin( fmin(2. * g - 1., 3. - 2. * g), fmin(2. * h + 1., 1. - 2. * h), ) * sign; b = 2. * b - 1.; c = 2. * c - 1.; output.push(vec3a(a, b, c).normalize_or_zero()); } output }