From ce29ce6ad108d66001d900d64266bded757a2666 Mon Sep 17 00:00:00 2001 From: _ <_@_> Date: Mon, 21 Feb 2022 00:44:03 +0000 Subject: [PATCH] converting a very simple two-mesh GLB to IQM --- Cargo.lock | 277 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 + src/main.rs | 155 +++++++++++++++++++---------- 3 files changed, 383 insertions(+), 51 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 58ecb14..be8a6db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,15 +2,292 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "adler32" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bytemuck" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439989e6b8c38d1b6570a384ef1e49c8848128f5a97f3914baef02920842712f" + [[package]] name = "byteorder" version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "deflate" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174" +dependencies = [ + "adler32", + "byteorder", +] + +[[package]] +name = "glam" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4fa84eead97d5412b2a20aed4d66612a97a9e41e08eababdb9ae2bf88667490" + +[[package]] +name = "gltf" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00e0a0eace786193fc83644907097285396360e9e82e30f81a21e9b1ba836a3e" +dependencies = [ + "base64", + "byteorder", + "gltf-json", + "image", + "lazy_static", +] + +[[package]] +name = "gltf-derive" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdd53d6e284bb2bf02a6926e4cc4984978c1990914d6cd9deae4e31cf37cd113" +dependencies = [ + "inflections", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "gltf-json" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9949836a9ec5e7f83f76fb9bbcbc77f254a577ebbdb0820867bc11979ef97cad" +dependencies = [ + "gltf-derive", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "image" +version = "0.23.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "jpeg-decoder", + "num-iter", + "num-rational", + "num-traits", + "png", +] + +[[package]] +name = "inflections" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a257582fdcde896fd96463bf2d40eefea0580021c0712a0e2b028b60b47a837a" + +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + +[[package]] +name = "jpeg-decoder" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "miniz_oxide" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" +dependencies = [ + "adler32", +] + [[package]] name = "model_converter" version = "0.1.0" dependencies = [ "byteorder", + "glam", + "gltf", ] + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "png" +version = "0.16.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6" +dependencies = [ + "bitflags", + "crc32fast", + "deflate", + "miniz_oxide", +] + +[[package]] +name = "proc-macro2" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" + +[[package]] +name = "serde" +version = "1.0.136" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" + +[[package]] +name = "serde_derive" +version = "1.0.136" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "syn" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" diff --git a/Cargo.toml b/Cargo.toml index 2cee40e..f6da9e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,5 @@ edition = "2021" [dependencies] byteorder = "1.4.3" +glam = "0.20.2" +gltf = "1.0.0" diff --git a/src/main.rs b/src/main.rs index 28c35c8..05d821c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,59 +3,111 @@ use std::{ io::Write, }; +use glam::{ + Mat4, + Vec3, +}; + fn main () { - let vertexes = [ - [-1.0, -1.0, -1.0], - [ 1.0, -1.0, -1.0], - [ 1.0, 1.0, -1.0], - [-1.0, 1.0, -1.0], - - [-1.0, -1.0, 1.0], - [ 1.0, -1.0, 1.0], - [ 1.0, 1.0, 1.0], - [-1.0, 1.0, 1.0], - ]; + let (document, buffers, _images) = gltf::import ("input.glb").unwrap (); + let buffer = buffers.get (0).unwrap (); - let triangles = [ - [0, 2, 1], - [0, 3, 2], + 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, + }; - [0, 5, 1], - [1, 6, 2], - [2, 7, 3], - [3, 4, 0], + let m = gltf_node_get_mat4 (&node); - [0, 4, 5], - [1, 5, 6], - [2, 6, 7], - [3, 7, 4], - - [4, 6, 5], - [4, 7, 6], - ]; + 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 mut texts = Vec::default (); - - let mesh = iqm::Mesh { - name: u32::try_from (texts.len ()).unwrap (), - material: 0, - first_vertex: 0, - num_vertexes, - first_triangle: 0, - num_triangles, - }; - texts.push ("Cube"); - - let meshes = vec! [ - mesh, - ]; - - let num_text: usize = texts.iter () - .map (|s| s.len () + 1) - .sum (); + let num_text = texts.len (); let num_text = u32::try_from (num_text).unwrap (); let num_meshes = u32::try_from (meshes.len ()).unwrap (); @@ -69,7 +121,7 @@ fn main () { let filesize = ofs_text + num_text; - let mut f = File::create ("cube.iqm").unwrap (); + let mut f = File::create ("output.iqm").unwrap (); f.write_all (b"INTERQUAKEMODEL\0").unwrap (); @@ -151,7 +203,7 @@ fn main () { f.write_all (&(3u32.to_le_bytes ())).unwrap (); // offset - f.write_all (&(0xA8u32.to_le_bytes ())).unwrap (); + f.write_all (&((ofs_vertexarrays + 5 * 4 * 1).to_le_bytes ())).unwrap (); // Vertexes @@ -170,10 +222,11 @@ fn main () { } // Text - for s in texts { - f.write_all (s.as_bytes ()).unwrap (); - f.write_all (b"\0").unwrap (); - } + 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