diff --git a/rust/mhgd/src/lightwave_object.rs b/rust/mhgd/src/lightwave_object.rs index 4a55cb0..acfe0e9 100644 --- a/rust/mhgd/src/lightwave_object.rs +++ b/rust/mhgd/src/lightwave_object.rs @@ -4,13 +4,14 @@ use godot::builtin::{ VariantArray, Vector2, Vector3, }; use godot::engine::mesh::{ArrayFormat, ArrayType, PrimitiveType}; -use godot::engine::{ArrayMesh, PackedScene}; +use godot::engine::{ArrayMesh, SurfaceTool}; use godot::obj::{EngineEnum, Gd}; -use godot::prelude::{Array, GodotClass, Share, ToVariant}; -use itertools::Itertools; +use godot::prelude::{godot_warn, Array, GodotClass, Share, ToVariant}; +use lightwave_3d::iff::Chunk; +use lightwave_3d::lwo2::tags::point_list::PointList; +use lightwave_3d::lwo2::tags::polygon_list::PolygonLists; use lightwave_3d::lwo2::tags::Tag; use lightwave_3d::LightWaveObject; -use std::fs::File; #[derive(GodotClass)] #[class(init)] @@ -28,129 +29,108 @@ pub fn lightwave_to_gd(lightwave: LightWaveObject) -> Gd { let mut mesh = ArrayMesh::new(); let mut arrays: Option = None; + let mut vert_count = 0; + for tag in lightwave.data { match tag { Tag::PointList(points) => { - if let Some(arrays) = &arrays { - mesh.add_surface_from_arrays( - PrimitiveType::PRIMITIVE_TRIANGLES, - arrays.share(), - Array::new(), - Dictionary::new(), - ArrayFormat::ARRAY_FORMAT_NORMAL, - ); - } + try_commit(&mut mesh, &arrays); + vert_count = points.point_location.len(); + let mut ars = Array::new(); ars.resize(ArrayType::ARRAY_MAX.ord() as usize); - let mut norm = PackedVector3Array::new(); - norm.resize(points.point_location.len()); - ars.set(ArrayType::ARRAY_NORMAL.ord() as usize, norm.to_variant()); + ars.set( ArrayType::ARRAY_VERTEX.ord() as usize, - PackedVector3Array::from( - points - .point_location - .iter() - .map(|[x, y, z]| Vector3 { - x: *x, - y: *y, - z: *z, - }) - .collect::>() - .as_slice(), - ) - .to_variant(), + collect_points(points).to_variant(), ); arrays = Some(ars); } - Tag::VertexMapping(vmap) => { - if let b"TXUV" = &vmap.kind { + Tag::VertexMapping(vmap) => match &vmap.kind { + b"TXUV" => { if let Some(arrays) = &mut arrays { - arrays.set( - ArrayType::ARRAY_TEX_UV.ord() as usize, - PackedVector2Array::from( - vmap.mapping - .iter() - .map(|uv| Vector2 { - x: uv.value[0], - y: uv.value[1], - }) - .collect::>() - .as_slice(), - ) - .to_variant(), - ); + let mut arr = PackedVector2Array::new(); + arr.resize(vert_count); + + for uv in vmap.data.mapping { + arr.set( + uv.vert as usize, + Vector2 { + x: uv.value[0], + y: uv.value[1], + }, + ); + } + + arrays.set(ArrayType::ARRAY_TEX_UV.ord() as usize, arr.to_variant()); } } - } + x => godot_warn!("{}", String::from_utf8(x.to_vec()).unwrap()), + }, Tag::PolygonList(polygons) => match &polygons.kind { b"FACE" => { if let Some(arrays) = &mut arrays { - arrays.set( - ArrayType::ARRAY_INDEX.ord() as usize, - PackedInt32Array::from( - get_rendering_vertex_indices( - polygons - .polygons - .iter() - .flat_map(|it| it.vert.iter().map(|it| *it as i32)) - .collect::>(), - ) - .as_slice(), - ) - .to_variant(), - ); + let indices = collect_polygons(polygons); + arrays.set(ArrayType::ARRAY_INDEX.ord() as usize, indices.to_variant()); } } - _ => panic!(), + x => godot_warn!("{}", String::from_utf8(x.to_vec()).unwrap()), }, _ => (), } } - if let Some(arrays) = &arrays { + try_commit(&mut mesh, &arrays); + let mut out_mesh = ArrayMesh::new(); + for i in 0..mesh.get_surface_count() { + let mut tool = SurfaceTool::new(); + tool.create_from(mesh.share().upcast(), i); + tool.generate_normals(false); + tool.generate_tangents(); + try_commit(&mut out_mesh, &Some(tool.commit_to_arrays())); + } + out_mesh +} + +fn try_commit(mesh: &mut ArrayMesh, arrays: &Option) { + if let Some(arrays) = arrays { mesh.add_surface_from_arrays( PrimitiveType::PRIMITIVE_TRIANGLES, arrays.share(), Array::new(), Dictionary::new(), - ArrayFormat::ARRAY_FORMAT_VERTEX, + ArrayFormat::ARRAY_FORMAT_NORMAL, ); } - - mesh.regen_normal_maps(); - - mesh } -fn get_rendering_vertex_indices(strip: Vec) -> Vec { - if strip.len() == 2 { - return vec![strip[0], strip[1], strip[0]]; - } - - let mut p = strip.into_iter(); - let mut vertex_indices = vec![]; - - let mut f1 = p.next().unwrap(); - let mut f2 = p.next().unwrap(); - let mut face_direction = 1; - for f3 in p { - // face_direction *= -1; - if f1 != f2 && f2 != f3 && f3 != f1 { - if face_direction > 0 { - vertex_indices.push(f3); - vertex_indices.push(f2); - vertex_indices.push(f1); - } else { - vertex_indices.push(f2); - vertex_indices.push(f3); - vertex_indices.push(f1); - } - } - - f1 = f2; - f2 = f3; - } - - vertex_indices +fn collect_points(chunk: Chunk) -> PackedVector3Array { + PackedVector3Array::from( + chunk + .data + .point_location + .into_iter() + .map(|[x, y, z]| Vector3 { x, y, z }) + .collect::>() + .as_slice(), + ) +} + +fn collect_polygons(chunk: Chunk) -> PackedInt32Array { + debug_assert!(chunk.polygons.len() >= 3, "{:?}", chunk); + PackedInt32Array::from( + chunk + .data + .polygons + .into_iter() + .flat_map(|mut it| { + let fan_v = it.vert.remove(0) as i32; + it.vert + .windows(2) + .flat_map(|w| [w[1] as i32, w[0] as i32, fan_v]) + .collect::>() + }) + .collect::>() + .as_slice(), + ) }