use std::borrow::Cow; use crate::proto::{Mesh, Texture, texture::Format}; use anyhow::Result; use glam::{Vec2, Vec3A, vec2, vec3a}; use weareshared::{ packets::Resource, resources::{Image, 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_coordinates(), &m.uv_offset_and_scale); let normals = decode_normals(m.normals(), normal_table); let texture = decode_texture(&m.texture[0]); 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(()), tex_albedo: Some(store.set(&texture)?), ..Default::default() })?) } fn decode_texture(texture: &Texture) -> Image<'static> { match texture.format() { Format::Jpg => Image(Cow::Owned(texture.data[0].clone())), Format::Dxt1 => todo!(), Format::Etc1 => todo!(), Format::Pvrtc2 => todo!(), Format::Pvrtc4 => todo!(), Format::CrnDxt1 => todo!(), } } fn decode_texcoords(uv: &[u8], offset_and_scale: &[f32]) -> Option> { if uv.is_empty() { return None; } let count = (uv.len() - 4) / 4; let u_mod = u16::from_le_bytes([uv[0], uv[1]]); let v_mod = u16::from_le_bytes([uv[2], uv[3]]); let uv = &uv[4..]; let (offset, scale) = if offset_and_scale.len() == 4 { ( vec2(offset_and_scale[0], offset_and_scale[1]), vec2(offset_and_scale[2], offset_and_scale[3]), ) } else { (Vec2::ZERO, vec2(1. / u_mod as f32, -1. / v_mod as f32)) }; let (mut u, mut v) = (0u16, 0u16); let mut texcoords = Vec::new(); for i in 0..count { u = u.wrapping_add((uv[count * 0 + i] as u16) + ((uv[count * 2 + i] as u16) << 8)); v = v.wrapping_add((uv[count * 1 + i] as u16) + ((uv[count * 3 + i] as u16) << 8)); u %= u_mod; v %= v_mod; let c = vec2(u as f32, v as f32); texcoords.push(scale * (offset + c)) } 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 }