use std::{ fs::File, io::Write, }; use glam::{ Mat4, Vec3, }; fn main () { let (document, buffers, _images) = gltf::import ("input.glb").unwrap (); let buffer = buffers.get (0).unwrap (); let mut vertexes = Vec::default (); let mut triangles = Vec::default (); let mut meshes = Vec::default (); let mut texts = String::default (); for node in document.nodes () { let mesh = match node.mesh () { None => continue, Some (x) => x, }; let m = gltf_node_get_mat4 (&node); for prim in mesh.primitives () { assert_eq! (prim.mode (), gltf::mesh::Mode::Triangles); let indices = prim.indices ().unwrap (); let indices_view = indices.view ().unwrap (); let indices_offset = indices.offset () + indices_view.offset (); let indices_slice = &buffer [indices_offset..(indices_offset + indices.count () * 2)]; let pos = prim.get (&gltf::Semantic::Positions).unwrap (); let pos_view = pos.view ().unwrap (); let pos_offset = pos.offset () + pos_view.offset (); let pos_slice = &buffer [pos_offset..(pos_offset + pos.count () * 4 * 3)]; let first_vertex = vertexes.len (); let mesh = iqm::Mesh { name: u32::try_from (texts.len ()).unwrap (), material: 0, first_vertex: u32::try_from (first_vertex).unwrap (), num_vertexes: u32::try_from (indices_slice.len () / 2).unwrap (), // num_vertexes: u32::try_from (3).unwrap (), first_triangle: u32::try_from (triangles.len ()).unwrap (), num_triangles: u32::try_from (indices_slice.len () / 6).unwrap (), //num_triangles: u32::try_from (1).unwrap (), }; texts.push_str ("\0"); meshes.push (mesh); for chunk in indices_slice.chunks_exact (2 * 3) { let read_idx = |i: usize| u16::from_le_bytes ([chunk [i * 2 + 0], chunk [i * 2 + 1]]); let idxs = [ read_idx (0), read_idx (1), read_idx (2), ]; let read_pos_coord = |i| f32::from_le_bytes ([ pos_slice [i * 4 + 0], pos_slice [i * 4 + 1], pos_slice [i * 4 + 2], pos_slice [i * 4 + 3], ]); let read_pos = move |i| { let i = usize::try_from (i).unwrap (); m.transform_point3 (Vec3::new ( read_pos_coord (i * 3 + 0), read_pos_coord (i * 3 + 1), read_pos_coord (i * 3 + 2), )) }; let verts = [ read_pos (idxs [0]), read_pos (idxs [2]), read_pos (idxs [1]), ]; let tri_start = u32::try_from (vertexes.len ()).unwrap (); triangles.push ([ tri_start + 0, tri_start + 1, tri_start + 2, ]); for v in verts { vertexes.push (v.to_array ()); } } } } let vertexes = vertexes; let triangles = triangles; let meshes = meshes; let texts = texts; let num_vertexes = u32::try_from (vertexes.len ()).unwrap (); let num_triangles = u32::try_from (triangles.len ()).unwrap (); let num_text = texts.len (); let num_text = u32::try_from (num_text).unwrap (); let num_meshes = u32::try_from (meshes.len ()).unwrap (); let num_vertexarrays = 1u32; let header_len = 124u32; let ofs_meshes = header_len; let ofs_vertexarrays = ofs_meshes + num_meshes * 6 * 4; let ofs_triangles = ofs_vertexarrays + num_vertexarrays * 5 * 4 + num_vertexes * 3 * 4; let ofs_text = ofs_triangles + num_triangles * 3 * 4; let filesize = ofs_text + num_text; let mut f = File::create ("output.iqm").unwrap (); f.write_all (b"INTERQUAKEMODEL\0").unwrap (); f.write_all (&(2u32.to_le_bytes ())).unwrap (); // filesize f.write_all (&(filesize.to_le_bytes ())).unwrap (); // flags f.write_all (&(0u32.to_le_bytes ())).unwrap (); // num_text, ofs_text f.write_all (&(num_text.to_le_bytes ())).unwrap (); f.write_all (&(ofs_text.to_le_bytes ())).unwrap (); // num_meshes, ofs_meshes f.write_all (&(num_meshes.to_le_bytes ())).unwrap (); f.write_all (&(ofs_meshes.to_le_bytes ())).unwrap (); // num_vertexarrays, num_vertexes, ofs_vertexarrays f.write_all (&(num_vertexarrays.to_le_bytes ())).unwrap (); f.write_all (&(num_vertexes.to_le_bytes ())).unwrap (); f.write_all (&(ofs_vertexarrays.to_le_bytes ())).unwrap (); // num_triangles, ofs_triangles, ofs_adjacency f.write_all (&(num_triangles.to_le_bytes ())).unwrap (); f.write_all (&(ofs_triangles.to_le_bytes ())).unwrap (); f.write_all (&(0u32.to_le_bytes ())).unwrap (); // num_joints, ofs_joints f.write_all (&(0u32.to_le_bytes ())).unwrap (); f.write_all (&(0u32.to_le_bytes ())).unwrap (); // num_poses, ofs_poses f.write_all (&(0u32.to_le_bytes ())).unwrap (); f.write_all (&(0u32.to_le_bytes ())).unwrap (); // num_anims, ofs_anims f.write_all (&(0u32.to_le_bytes ())).unwrap (); f.write_all (&(0u32.to_le_bytes ())).unwrap (); // num_frames, num_framechannels, ofs_frames, ofs_bounds f.write_all (&(0u32.to_le_bytes ())).unwrap (); f.write_all (&(0u32.to_le_bytes ())).unwrap (); f.write_all (&(0u32.to_le_bytes ())).unwrap (); f.write_all (&(0u32.to_le_bytes ())).unwrap (); // num_comment, ofs_comment f.write_all (&(0u32.to_le_bytes ())).unwrap (); f.write_all (&(0u32.to_le_bytes ())).unwrap (); // num_extensions, ofs_extensions f.write_all (&(0u32.to_le_bytes ())).unwrap (); f.write_all (&(0u32.to_le_bytes ())).unwrap (); // Meshes for mesh in meshes { f.write_all (&(mesh.name.to_le_bytes ())).unwrap (); f.write_all (&(mesh.material.to_le_bytes ())).unwrap (); f.write_all (&(mesh.first_vertex.to_le_bytes ())).unwrap (); f.write_all (&(mesh.num_vertexes.to_le_bytes ())).unwrap (); f.write_all (&(mesh.first_triangle.to_le_bytes ())).unwrap (); f.write_all (&(mesh.num_triangles.to_le_bytes ())).unwrap (); } // Vertex arrays // type f.write_all (&(0u32.to_le_bytes ())).unwrap (); // flags f.write_all (&(0u32.to_le_bytes ())).unwrap (); // format f.write_all (&(7u32.to_le_bytes ())).unwrap (); // size f.write_all (&(3u32.to_le_bytes ())).unwrap (); // offset f.write_all (&((ofs_vertexarrays + 5 * 4 * 1).to_le_bytes ())).unwrap (); // Vertexes for t in vertexes { for x in t { f.write_all (&(f32::to_le_bytes (x))).unwrap (); } } // Triangles for t in triangles { for x in t { f.write_all (&(u32::to_le_bytes (x))).unwrap (); } } // Text f.write_all (texts.as_bytes ()).unwrap (); } fn gltf_node_get_mat4 (node: &gltf::Node) -> Mat4 { Mat4::from_cols_array_2d (&node.transform ().matrix ()) } /// IQM structures as written to disk mod iqm { pub struct Mesh { pub name: u32, pub material: u32, pub first_vertex: u32, pub num_vertexes: u32, pub first_triangle: u32, pub num_triangles: u32, } struct VertexArray { r#type: u32, flags: u32, format: u32, size: u32, offset: u32, } struct Triangle { vertex: [u32; 3], } struct Vertex { position: [f32; 3], } }