diff --git a/Cargo.lock b/Cargo.lock index eedda2f..405028a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1301,10 +1301,12 @@ dependencies = [ "eframe", "egui_extras", "env_logger", + "fs_extra", "glam", "image", "log", "serialport", + "tobj", ] [[package]] @@ -1455,6 +1457,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "futures-core" version = "0.3.32" @@ -3908,6 +3916,15 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tobj" +version = "4.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2da83817ac7401436633efc35c19edae9f326fa741fae775a1caa406de9db07c" +dependencies = [ + "ahash", +] + [[package]] name = "toml_datetime" version = "1.1.1+spec-1.1.0" diff --git a/Cargo.toml b/Cargo.toml index 54fddd7..9bd06cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ name = "eskin-model-player" version = "0.5.0" edition = "2024" +build = "build.rs" [dependencies] eframe = { version = "0.34.2", features = ["default", "wgpu", "__screenshot"] } @@ -15,3 +16,8 @@ egui_extras = { version = "0.34.2", features = ["image"] } crossbeam-channel = "0.5.15" crc = "3.4.0" log = "0.4.29" +tobj = "4.0.4" + +[build-dependencies] +anyhow = "1.0.102" +fs_extra = "1.3.0" diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..d16198d --- /dev/null +++ b/build.rs @@ -0,0 +1,33 @@ +use std::{env, fs, path::PathBuf}; + +use anyhow::Result; +use fs_extra::{copy_items, dir::CopyOptions}; + +fn main() -> Result<()> { + let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?); + let source_dir = manifest_dir.join("res"); + let out_dir = PathBuf::from(env::var("OUT_DIR")?); + let resource_dir = out_dir.join("res"); + + let mut copy_options = CopyOptions::new(); + copy_options.overwrite = true; + + println!("cargo:rerun-if-changed={}", source_dir.display()); + + if resource_dir.exists() { + fs::remove_dir_all(&resource_dir)?; + } + + if source_dir.exists() { + let items = fs::read_dir(&source_dir)? + .map(|entry| entry.map(|entry| entry.path())) + .collect::, _>>()?; + + fs::create_dir_all(&resource_dir)?; + copy_items(&items, &resource_dir, ©_options)?; + } + + println!("cargo:rustc-env=RESOURCE_DIR={}", resource_dir.display()); + + Ok(()) +} diff --git a/res/cube-diffuse.jpg b/res/cube-diffuse.jpg new file mode 100644 index 0000000..c89b31d Binary files /dev/null and b/res/cube-diffuse.jpg differ diff --git a/res/cube-normal.png b/res/cube-normal.png new file mode 100644 index 0000000..5bbac0a Binary files /dev/null and b/res/cube-normal.png differ diff --git a/res/cube.mtl b/res/cube.mtl new file mode 100644 index 0000000..6be388c --- /dev/null +++ b/res/cube.mtl @@ -0,0 +1,14 @@ +# Blender MTL File: 'cube.blend' +# Material Count: 1 + +newmtl Material.001 +Ns 323.999994 +Ka 1.000000 1.000000 1.000000 +Kd 0.800000 0.800000 0.800000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.450000 +d 1.000000 +illum 2 +map_Bump cube-normal.png +map_Kd cube-diffuse.jpg diff --git a/res/cube.obj b/res/cube.obj new file mode 100644 index 0000000..03b3bca --- /dev/null +++ b/res/cube.obj @@ -0,0 +1,1143 @@ +# Blender v2.82 (sub 7) OBJ File: 'cube.blend' +# www.blender.org +mtllib cube.mtl +o Cube_Finished_Cube.001 +v 0.900000 0.900000 -1.000000 +v 0.900000 1.000000 -0.900000 +v 1.000000 0.900000 -0.900000 +v 0.900000 0.930907 -0.995104 +v 0.900000 0.958769 -0.980909 +v 0.930907 0.900000 -0.995104 +v 0.931727 0.931906 -0.989305 +v 0.930693 0.957414 -0.975905 +v 0.958769 0.900000 -0.980909 +v 0.957466 0.930772 -0.975834 +v 0.952912 0.952912 -0.966338 +v 0.930907 0.995104 -0.900000 +v 0.958769 0.980909 -0.900000 +v 0.900000 0.995104 -0.930907 +v 0.931906 0.989305 -0.931727 +v 0.957414 0.975905 -0.930693 +v 0.900000 0.980909 -0.958769 +v 0.930772 0.975834 -0.957466 +v 0.952912 0.966338 -0.952912 +v 0.995104 0.900000 -0.930907 +v 0.980909 0.900000 -0.958769 +v 0.995104 0.930907 -0.900000 +v 0.989305 0.931727 -0.931906 +v 0.975905 0.930693 -0.957414 +v 0.980909 0.958769 -0.900000 +v 0.975834 0.957466 -0.930772 +v 0.966338 0.952912 -0.952912 +v 0.900000 -1.000000 -0.900000 +v 0.900000 -0.900000 -1.000000 +v 1.000000 -0.900000 -0.900000 +v 0.900000 -0.995104 -0.930907 +v 0.900000 -0.980909 -0.958769 +v 0.930907 -0.995104 -0.900000 +v 0.931727 -0.989305 -0.931906 +v 0.930693 -0.975905 -0.957414 +v 0.958769 -0.980909 -0.900000 +v 0.957466 -0.975834 -0.930772 +v 0.952912 -0.966338 -0.952912 +v 0.930907 -0.900000 -0.995104 +v 0.958769 -0.900000 -0.980909 +v 0.900000 -0.930907 -0.995104 +v 0.931906 -0.931727 -0.989305 +v 0.957414 -0.930693 -0.975905 +v 0.900000 -0.958769 -0.980909 +v 0.930772 -0.957466 -0.975834 +v 0.952912 -0.952912 -0.966338 +v 0.995104 -0.930907 -0.900000 +v 0.980909 -0.958769 -0.900000 +v 0.995104 -0.900000 -0.930907 +v 0.989305 -0.931906 -0.931727 +v 0.975905 -0.957414 -0.930693 +v 0.980909 -0.900000 -0.958769 +v 0.975834 -0.930772 -0.957466 +v 0.966338 -0.952912 -0.952912 +v 1.000000 0.900000 0.900000 +v 0.900000 1.000000 0.900000 +v 0.900000 0.900000 1.000000 +v 0.995104 0.930907 0.900000 +v 0.980909 0.958769 0.900000 +v 0.995104 0.900000 0.930907 +v 0.989305 0.931906 0.931727 +v 0.975905 0.957414 0.930693 +v 0.980909 0.900000 0.958769 +v 0.975834 0.930772 0.957466 +v 0.966338 0.952912 0.952912 +v 0.900000 0.995104 0.930907 +v 0.900000 0.980909 0.958769 +v 0.930907 0.995104 0.900000 +v 0.931727 0.989305 0.931906 +v 0.930693 0.975905 0.957414 +v 0.958769 0.980909 0.900000 +v 0.957466 0.975834 0.930772 +v 0.952912 0.966338 0.952912 +v 0.930907 0.900000 0.995104 +v 0.958769 0.900000 0.980909 +v 0.900000 0.930907 0.995104 +v 0.931906 0.931727 0.989305 +v 0.957414 0.930693 0.975905 +v 0.900000 0.958769 0.980909 +v 0.930772 0.957466 0.975834 +v 0.952912 0.952912 0.966338 +v 1.000000 -0.900000 0.900000 +v 0.900000 -0.900000 1.000000 +v 0.900000 -1.000000 0.900000 +v 0.995104 -0.900000 0.930907 +v 0.980909 -0.900000 0.958769 +v 0.995104 -0.930907 0.900000 +v 0.989305 -0.931727 0.931906 +v 0.975905 -0.930693 0.957414 +v 0.980909 -0.958769 0.900000 +v 0.975834 -0.957466 0.930772 +v 0.966338 -0.952912 0.952912 +v 0.900000 -0.930907 0.995104 +v 0.900000 -0.958769 0.980909 +v 0.930907 -0.900000 0.995104 +v 0.931727 -0.931906 0.989305 +v 0.930693 -0.957414 0.975905 +v 0.958769 -0.900000 0.980909 +v 0.957466 -0.930772 0.975834 +v 0.952912 -0.952912 0.966338 +v 0.930907 -0.995104 0.900000 +v 0.958769 -0.980909 0.900000 +v 0.900000 -0.995104 0.930907 +v 0.931906 -0.989305 0.931727 +v 0.957414 -0.975905 0.930693 +v 0.900000 -0.980909 0.958769 +v 0.930772 -0.975834 0.957466 +v 0.952912 -0.966338 0.952912 +v -0.900000 0.900000 -1.000000 +v -1.000000 0.900000 -0.900000 +v -0.900000 1.000000 -0.900000 +v -0.930907 0.900000 -0.995104 +v -0.958769 0.900000 -0.980909 +v -0.900000 0.930907 -0.995104 +v -0.931906 0.931727 -0.989305 +v -0.957414 0.930693 -0.975905 +v -0.900000 0.958769 -0.980909 +v -0.930772 0.957466 -0.975834 +v -0.952912 0.952912 -0.966338 +v -0.995104 0.930907 -0.900000 +v -0.980909 0.958769 -0.900000 +v -0.995104 0.900000 -0.930907 +v -0.989305 0.931906 -0.931727 +v -0.975905 0.957414 -0.930693 +v -0.980909 0.900000 -0.958769 +v -0.975834 0.930772 -0.957466 +v -0.966338 0.952912 -0.952912 +v -0.900000 0.995104 -0.930907 +v -0.900000 0.980909 -0.958769 +v -0.930907 0.995104 -0.900000 +v -0.931727 0.989305 -0.931906 +v -0.930693 0.975905 -0.957414 +v -0.958769 0.980909 -0.900000 +v -0.957466 0.975834 -0.930772 +v -0.952912 0.966338 -0.952912 +v -1.000000 -0.900000 -0.900000 +v -0.900000 -0.900000 -1.000000 +v -0.900000 -1.000000 -0.900000 +v -0.995104 -0.900000 -0.930907 +v -0.980909 -0.900000 -0.958769 +v -0.995104 -0.930907 -0.900000 +v -0.989305 -0.931727 -0.931906 +v -0.975905 -0.930693 -0.957414 +v -0.980909 -0.958769 -0.900000 +v -0.975834 -0.957466 -0.930772 +v -0.966338 -0.952912 -0.952912 +v -0.900000 -0.930907 -0.995104 +v -0.900000 -0.958769 -0.980909 +v -0.930907 -0.900000 -0.995104 +v -0.931727 -0.931906 -0.989305 +v -0.930693 -0.957414 -0.975905 +v -0.958769 -0.900000 -0.980909 +v -0.957466 -0.930772 -0.975834 +v -0.952912 -0.952912 -0.966338 +v -0.930907 -0.995104 -0.900000 +v -0.958769 -0.980909 -0.900000 +v -0.900000 -0.995104 -0.930907 +v -0.931906 -0.989305 -0.931727 +v -0.957414 -0.975905 -0.930693 +v -0.900000 -0.980909 -0.958769 +v -0.930772 -0.975834 -0.957466 +v -0.952912 -0.966338 -0.952912 +v -1.000000 0.900000 0.900000 +v -0.900000 0.900000 1.000000 +v -0.900000 1.000000 0.900000 +v -0.995104 0.900000 0.930907 +v -0.980909 0.900000 0.958769 +v -0.995104 0.930907 0.900000 +v -0.989305 0.931727 0.931906 +v -0.975905 0.930693 0.957414 +v -0.980909 0.958769 0.900000 +v -0.975834 0.957466 0.930772 +v -0.966338 0.952912 0.952912 +v -0.900000 0.930907 0.995104 +v -0.900000 0.958769 0.980909 +v -0.930907 0.900000 0.995104 +v -0.931727 0.931906 0.989305 +v -0.930693 0.957414 0.975905 +v -0.958769 0.900000 0.980909 +v -0.957466 0.930772 0.975834 +v -0.952912 0.952912 0.966338 +v -0.930907 0.995104 0.900000 +v -0.958769 0.980909 0.900000 +v -0.900000 0.995104 0.930907 +v -0.931906 0.989305 0.931727 +v -0.957414 0.975905 0.930693 +v -0.900000 0.980909 0.958769 +v -0.930772 0.975834 0.957466 +v -0.952912 0.966338 0.952912 +v -0.900000 -1.000000 0.900000 +v -0.900000 -0.900000 1.000000 +v -1.000000 -0.900000 0.900000 +v -0.900000 -0.995104 0.930907 +v -0.900000 -0.980909 0.958769 +v -0.930907 -0.995104 0.900000 +v -0.931727 -0.989305 0.931906 +v -0.930693 -0.975905 0.957414 +v -0.958769 -0.980909 0.900000 +v -0.957466 -0.975834 0.930772 +v -0.952912 -0.966338 0.952912 +v -0.930907 -0.900000 0.995104 +v -0.958769 -0.900000 0.980909 +v -0.900000 -0.930907 0.995104 +v -0.931906 -0.931727 0.989305 +v -0.957414 -0.930693 0.975905 +v -0.900000 -0.958769 0.980909 +v -0.930772 -0.957466 0.975834 +v -0.952912 -0.952912 0.966338 +v -0.995104 -0.930907 0.900000 +v -0.980909 -0.958769 0.900000 +v -0.995104 -0.900000 0.930907 +v -0.989305 -0.931906 0.931727 +v -0.975905 -0.957414 0.930693 +v -0.980909 -0.900000 0.958769 +v -0.975834 -0.930772 0.957466 +v -0.966338 -0.952912 0.952912 +vt 0.362500 0.512500 +vt 0.137500 0.737500 +vt 0.137500 0.512500 +vt 0.612500 0.012500 +vt 0.387500 0.237500 +vt 0.387500 0.012500 +vt 0.612500 0.762500 +vt 0.387500 0.987500 +vt 0.387500 0.762500 +vt 0.862500 0.512500 +vt 0.637500 0.737500 +vt 0.637500 0.512500 +vt 0.612500 0.512500 +vt 0.387500 0.737500 +vt 0.387500 0.512500 +vt 0.616363 0.487500 +vt 0.612500 0.491363 +vt 0.612500 0.487500 +vt 0.619846 0.487500 +vt 0.616488 0.491466 +vt 0.625000 0.487500 +vt 0.619677 0.491337 +vt 0.612500 0.494846 +vt 0.619114 0.494114 +vt 0.616346 0.494683 +vt 0.625000 0.491347 +vt 0.633637 0.512500 +vt 0.637500 0.508637 +vt 0.630154 0.512500 +vt 0.633512 0.508534 +vt 0.619846 0.512500 +vt 0.630323 0.508663 +vt 0.637500 0.505154 +vt 0.630886 0.505886 +vt 0.633654 0.505317 +vt 0.619683 0.508653 +vt 0.612500 0.508637 +vt 0.616363 0.512500 +vt 0.612500 0.505154 +vt 0.616466 0.508512 +vt 0.616337 0.505323 +vt 0.619114 0.505886 +vt 0.625000 0.494114 +vt 0.619114 0.500000 +vt 0.362500 0.508637 +vt 0.366363 0.512500 +vt 0.362500 0.505154 +vt 0.366466 0.508512 +vt 0.362500 0.500000 +vt 0.366337 0.505323 +vt 0.369846 0.512500 +vt 0.369114 0.505886 +vt 0.369683 0.508653 +vt 0.366347 0.500000 +vt 0.387500 0.491363 +vt 0.383637 0.487500 +vt 0.387500 0.487500 +vt 0.387500 0.494846 +vt 0.383534 0.491488 +vt 0.387500 0.505154 +vt 0.383663 0.494677 +vt 0.380154 0.487500 +vt 0.380886 0.494114 +vt 0.380317 0.491346 +vt 0.383653 0.505317 +vt 0.383637 0.512500 +vt 0.387500 0.508637 +vt 0.380154 0.512500 +vt 0.383512 0.508534 +vt 0.380323 0.508663 +vt 0.380886 0.505886 +vt 0.369114 0.500000 +vt 0.375000 0.505886 +vt 0.616363 0.737500 +vt 0.612500 0.741363 +vt 0.612500 0.737500 +vt 0.619846 0.737500 +vt 0.616488 0.741466 +vt 0.630154 0.737500 +vt 0.619677 0.741337 +vt 0.612500 0.744846 +vt 0.619114 0.744114 +vt 0.616346 0.744683 +vt 0.630317 0.741346 +vt 0.637500 0.741363 +vt 0.633637 0.737500 +vt 0.637500 0.744846 +vt 0.633534 0.741488 +vt 0.637500 0.750000 +vt 0.633664 0.744677 +vt 0.630886 0.744114 +vt 0.633653 0.750000 +vt 0.612500 0.758637 +vt 0.616363 0.762500 +vt 0.612500 0.755154 +vt 0.616466 0.758512 +vt 0.616337 0.755323 +vt 0.619846 0.762500 +vt 0.619114 0.755886 +vt 0.619683 0.758653 +vt 0.625000 0.744114 +vt 0.619114 0.750000 +vt 0.387500 0.741363 +vt 0.383637 0.737500 +vt 0.387500 0.744846 +vt 0.383534 0.741488 +vt 0.387500 0.755154 +vt 0.383663 0.744677 +vt 0.380154 0.737500 +vt 0.380886 0.744114 +vt 0.380317 0.741346 +vt 0.383653 0.755317 +vt 0.383637 0.762500 +vt 0.387500 0.758637 +vt 0.380154 0.762500 +vt 0.383512 0.758534 +vt 0.375000 0.762500 +vt 0.380323 0.758663 +vt 0.380886 0.755886 +vt 0.375000 0.758654 +vt 0.366363 0.737500 +vt 0.362500 0.741363 +vt 0.362500 0.737500 +vt 0.369846 0.737500 +vt 0.366488 0.741466 +vt 0.369677 0.741337 +vt 0.362500 0.744846 +vt 0.369114 0.744114 +vt 0.366347 0.744683 +vt 0.380886 0.750000 +vt 0.375000 0.744114 +vt 0.612500 0.258637 +vt 0.616363 0.262500 +vt 0.612500 0.262500 +vt 0.612500 0.255154 +vt 0.616466 0.258512 +vt 0.612500 0.244846 +vt 0.616337 0.255323 +vt 0.619846 0.262500 +vt 0.619114 0.255886 +vt 0.619683 0.258653 +vt 0.616346 0.244683 +vt 0.616363 0.237500 +vt 0.612500 0.241363 +vt 0.612500 0.237500 +vt 0.619846 0.237500 +vt 0.616488 0.241466 +vt 0.625000 0.237500 +vt 0.619677 0.241337 +vt 0.619114 0.244114 +vt 0.625000 0.241347 +vt 0.862500 0.508637 +vt 0.866363 0.512500 +vt 0.862500 0.505154 +vt 0.866466 0.508512 +vt 0.862500 0.500000 +vt 0.866337 0.505323 +vt 0.869846 0.512500 +vt 0.869114 0.505886 +vt 0.869683 0.508653 +vt 0.866347 0.500000 +vt 0.619114 0.250000 +vt 0.625000 0.255886 +vt 0.387500 0.241363 +vt 0.383637 0.237500 +vt 0.387500 0.244846 +vt 0.383534 0.241488 +vt 0.387500 0.255154 +vt 0.383663 0.244677 +vt 0.380154 0.237500 +vt 0.380886 0.244114 +vt 0.380317 0.241346 +vt 0.383653 0.255317 +vt 0.383637 0.262500 +vt 0.387500 0.258637 +vt 0.387500 0.262500 +vt 0.380154 0.262500 +vt 0.383512 0.258534 +vt 0.375000 0.262500 +vt 0.380323 0.258663 +vt 0.380886 0.255886 +vt 0.375000 0.258653 +vt 0.133637 0.512500 +vt 0.137500 0.508637 +vt 0.130154 0.512500 +vt 0.133512 0.508534 +vt 0.125000 0.512500 +vt 0.130323 0.508663 +vt 0.137500 0.505154 +vt 0.130886 0.505886 +vt 0.133653 0.505317 +vt 0.125000 0.508654 +vt 0.380886 0.250000 +vt 0.375000 0.244114 +vt 0.612500 0.008637 +vt 0.616363 0.012500 +vt 0.612500 0.005154 +vt 0.616466 0.008512 +vt 0.612500 0.000000 +vt 0.616337 0.005323 +vt 0.619846 0.012500 +vt 0.619114 0.005886 +vt 0.619683 0.008654 +vt 0.616346 0.000000 +vt 0.616363 0.987500 +vt 0.612500 0.991363 +vt 0.612500 0.987500 +vt 0.619846 0.987500 +vt 0.616488 0.991466 +vt 0.625000 0.987500 +vt 0.619677 0.991337 +vt 0.612500 0.994846 +vt 0.619114 0.994114 +vt 0.616346 0.994683 +vt 0.625000 0.991346 +vt 0.866363 0.737500 +vt 0.862500 0.741363 +vt 0.862500 0.737500 +vt 0.869846 0.737500 +vt 0.866488 0.741466 +vt 0.875000 0.737500 +vt 0.869677 0.741337 +vt 0.862500 0.744846 +vt 0.869114 0.744114 +vt 0.866346 0.744683 +vt 0.875000 0.741347 +vt 0.619114 0.000000 +vt 0.625000 0.005886 +vt 0.137500 0.741363 +vt 0.133637 0.737500 +vt 0.137500 0.744846 +vt 0.133534 0.741488 +vt 0.137500 0.750000 +vt 0.133663 0.744677 +vt 0.130154 0.737500 +vt 0.130886 0.744114 +vt 0.130317 0.741346 +vt 0.133653 0.750000 +vt 0.387500 0.991363 +vt 0.383637 0.987500 +vt 0.387500 0.994846 +vt 0.383534 0.991488 +vt 0.387500 1.000000 +vt 0.383663 0.994677 +vt 0.380154 0.987500 +vt 0.380886 0.994114 +vt 0.380317 0.991346 +vt 0.383654 1.000000 +vt 0.383637 0.012500 +vt 0.387500 0.008637 +vt 0.380154 0.012500 +vt 0.383512 0.008534 +vt 0.375000 0.012500 +vt 0.380323 0.008663 +vt 0.387500 0.005154 +vt 0.380886 0.005886 +vt 0.383653 0.005317 +vt 0.375000 0.008653 +vt 0.130886 0.750000 +vt 0.125000 0.744114 +vt 0.630886 0.750000 +vt 0.375000 0.755886 +vt 0.625000 0.244114 +vt 0.869114 0.500000 +vt 0.375000 0.255886 +vt 0.125000 0.505886 +vt 0.625000 0.994114 +vt 0.875000 0.744114 +vt 0.380886 1.000000 +vt 0.375000 0.005886 +vt 0.125000 0.737500 +vt 0.137500 0.500000 +vt 0.612500 1.000000 +vt 0.862500 0.750000 +vt 0.362500 0.750000 +vt 0.875000 0.512500 +vt 0.637500 0.500000 +vn 0.0779 -0.9939 -0.0779 +vn -0.0779 -0.9939 0.0779 +vn -0.0779 -0.9939 -0.0779 +vn -0.9939 0.0779 0.0779 +vn -0.9939 -0.0779 -0.0779 +vn -0.9939 -0.0779 0.0779 +vn 0.0779 0.0779 0.9939 +vn -0.0779 -0.0779 0.9939 +vn 0.0779 -0.0779 0.9939 +vn -0.0779 0.9939 -0.0779 +vn 0.0779 0.9939 0.0779 +vn 0.0779 0.9939 -0.0779 +vn 0.9939 0.0779 -0.0779 +vn 0.9939 -0.0779 0.0779 +vn 0.9939 -0.0779 -0.0779 +vn 0.0783 0.3064 -0.9486 +vn 0.3066 0.0787 -0.9485 +vn 0.0779 0.0779 -0.9939 +vn 0.0754 0.5855 -0.8071 +vn 0.3089 0.3098 -0.8992 +vn 0.0757 0.8072 -0.5853 +vn 0.2866 0.5718 -0.7687 +vn 0.5853 0.0757 -0.8072 +vn 0.5154 0.5156 -0.6844 +vn 0.5719 0.2870 -0.7685 +vn 0.2870 0.7685 -0.5719 +vn 0.3064 0.9486 -0.0783 +vn 0.0787 0.9485 -0.3066 +vn 0.5855 0.8071 -0.0754 +vn 0.3098 0.8992 -0.3089 +vn 0.8072 0.5853 -0.0757 +vn 0.5718 0.7687 -0.2866 +vn 0.5156 0.6844 -0.5154 +vn 0.7685 0.5719 -0.2870 +vn 0.9486 0.0783 -0.3064 +vn 0.9485 0.3066 -0.0787 +vn 0.8071 0.0754 -0.5855 +vn 0.8992 0.3089 -0.3098 +vn 0.7687 0.2866 -0.5718 +vn 0.6844 0.5154 -0.5156 +vn 0.0783 -0.9486 -0.3064 +vn 0.3066 -0.9485 -0.0787 +vn 0.0754 -0.8071 -0.5855 +vn 0.3089 -0.8992 -0.3098 +vn 0.0757 -0.5853 -0.8072 +vn 0.2866 -0.7687 -0.5718 +vn 0.5853 -0.8072 -0.0757 +vn 0.5154 -0.6844 -0.5156 +vn 0.5719 -0.7685 -0.2870 +vn 0.2870 -0.5719 -0.7685 +vn 0.3064 -0.0783 -0.9486 +vn 0.0787 -0.3066 -0.9485 +vn 0.0779 -0.0779 -0.9939 +vn 0.5855 -0.0754 -0.8071 +vn 0.3098 -0.3089 -0.8992 +vn 0.8072 -0.0757 -0.5853 +vn 0.5718 -0.2866 -0.7687 +vn 0.5156 -0.5154 -0.6844 +vn 0.7685 -0.2870 -0.5719 +vn 0.9486 -0.3064 -0.0783 +vn 0.9485 -0.0787 -0.3066 +vn 0.8071 -0.5855 -0.0754 +vn 0.8992 -0.3098 -0.3089 +vn 0.7687 -0.5718 -0.2866 +vn 0.6844 -0.5156 -0.5154 +vn 0.9486 0.3064 0.0783 +vn 0.9485 0.0787 0.3066 +vn 0.9939 0.0779 0.0779 +vn 0.8071 0.5855 0.0754 +vn 0.8992 0.3098 0.3089 +vn 0.5853 0.8072 0.0757 +vn 0.7687 0.5718 0.2866 +vn 0.8072 0.0757 0.5853 +vn 0.6844 0.5156 0.5154 +vn 0.7685 0.2870 0.5719 +vn 0.5719 0.7685 0.2870 +vn 0.0783 0.9486 0.3064 +vn 0.3066 0.9485 0.0787 +vn 0.0754 0.8071 0.5855 +vn 0.3089 0.8992 0.3098 +vn 0.0757 0.5853 0.8072 +vn 0.2866 0.7687 0.5718 +vn 0.5154 0.6844 0.5156 +vn 0.2870 0.5719 0.7685 +vn 0.3064 0.0783 0.9486 +vn 0.0787 0.3066 0.9485 +vn 0.5855 0.0754 0.8071 +vn 0.3098 0.3089 0.8992 +vn 0.5718 0.2866 0.7687 +vn 0.5156 0.5154 0.6844 +vn 0.9486 -0.0783 0.3064 +vn 0.9485 -0.3066 0.0787 +vn 0.8071 -0.0754 0.5855 +vn 0.8992 -0.3089 0.3098 +vn 0.5853 -0.0757 0.8072 +vn 0.7687 -0.2866 0.5718 +vn 0.8072 -0.5853 0.0757 +vn 0.6844 -0.5154 0.5156 +vn 0.7685 -0.5719 0.2870 +vn 0.5719 -0.2870 0.7685 +vn 0.0783 -0.3064 0.9486 +vn 0.3066 -0.0787 0.9485 +vn 0.0754 -0.5855 0.8071 +vn 0.3089 -0.3098 0.8992 +vn 0.0757 -0.8072 0.5853 +vn 0.2866 -0.5718 0.7687 +vn 0.5154 -0.5156 0.6844 +vn 0.2870 -0.7685 0.5719 +vn 0.3064 -0.9486 0.0783 +vn 0.0787 -0.9485 0.3066 +vn 0.0779 -0.9939 0.0779 +vn 0.5855 -0.8071 0.0754 +vn 0.3098 -0.8992 0.3089 +vn 0.5718 -0.7687 0.2866 +vn 0.5156 -0.6844 0.5154 +vn -0.3064 0.0783 -0.9486 +vn -0.0787 0.3066 -0.9485 +vn -0.0779 0.0779 -0.9939 +vn -0.5855 0.0754 -0.8071 +vn -0.3098 0.3089 -0.8992 +vn -0.8072 0.0757 -0.5853 +vn -0.5718 0.2866 -0.7687 +vn -0.0757 0.5853 -0.8072 +vn -0.5156 0.5154 -0.6844 +vn -0.2870 0.5719 -0.7685 +vn -0.7685 0.2870 -0.5719 +vn -0.9486 0.3064 -0.0783 +vn -0.9485 0.0787 -0.3066 +vn -0.9939 0.0779 -0.0779 +vn -0.8071 0.5855 -0.0754 +vn -0.8992 0.3098 -0.3089 +vn -0.5853 0.8072 -0.0757 +vn -0.7687 0.5718 -0.2866 +vn -0.6844 0.5156 -0.5154 +vn -0.5719 0.7685 -0.2870 +vn -0.0783 0.9486 -0.3064 +vn -0.3066 0.9485 -0.0787 +vn -0.0754 0.8071 -0.5855 +vn -0.3089 0.8992 -0.3098 +vn -0.2866 0.7687 -0.5718 +vn -0.5154 0.6844 -0.5156 +vn -0.9486 -0.0783 -0.3064 +vn -0.9485 -0.3066 -0.0787 +vn -0.8071 -0.0754 -0.5855 +vn -0.8992 -0.3089 -0.3098 +vn -0.5853 -0.0757 -0.8072 +vn -0.7687 -0.2866 -0.5718 +vn -0.8072 -0.5853 -0.0757 +vn -0.6844 -0.5154 -0.5156 +vn -0.7685 -0.5719 -0.2870 +vn -0.5719 -0.2870 -0.7685 +vn -0.0783 -0.3064 -0.9486 +vn -0.3066 -0.0787 -0.9485 +vn -0.0779 -0.0779 -0.9939 +vn -0.0754 -0.5855 -0.8071 +vn -0.3089 -0.3098 -0.8992 +vn -0.0757 -0.8072 -0.5853 +vn -0.2866 -0.5718 -0.7687 +vn -0.5154 -0.5156 -0.6844 +vn -0.2870 -0.7685 -0.5719 +vn -0.3064 -0.9486 -0.0783 +vn -0.0787 -0.9485 -0.3066 +vn -0.5855 -0.8071 -0.0754 +vn -0.3098 -0.8992 -0.3089 +vn -0.5718 -0.7687 -0.2866 +vn -0.5156 -0.6844 -0.5154 +vn -0.9486 0.0783 0.3064 +vn -0.9485 0.3066 0.0787 +vn -0.8071 0.0754 0.5855 +vn -0.8992 0.3089 0.3098 +vn -0.5853 0.0757 0.8072 +vn -0.7687 0.2866 0.5718 +vn -0.8072 0.5853 0.0757 +vn -0.6844 0.5154 0.5156 +vn -0.7685 0.5719 0.2870 +vn -0.5719 0.2870 0.7685 +vn -0.0783 0.3064 0.9486 +vn -0.3066 0.0787 0.9485 +vn -0.0779 0.0779 0.9939 +vn -0.0754 0.5855 0.8071 +vn -0.3089 0.3098 0.8992 +vn -0.0757 0.8072 0.5853 +vn -0.2866 0.5718 0.7687 +vn -0.5154 0.5156 0.6844 +vn -0.2870 0.7685 0.5719 +vn -0.3064 0.9486 0.0783 +vn -0.0787 0.9485 0.3066 +vn -0.0779 0.9939 0.0779 +vn -0.5855 0.8071 0.0754 +vn -0.3098 0.8992 0.3089 +vn -0.5718 0.7687 0.2866 +vn -0.5156 0.6844 0.5154 +vn -0.0783 -0.9486 0.3064 +vn -0.3066 -0.9485 0.0787 +vn -0.0754 -0.8071 0.5855 +vn -0.3089 -0.8992 0.3098 +vn -0.0757 -0.5853 0.8072 +vn -0.2866 -0.7687 0.5718 +vn -0.5853 -0.8072 0.0757 +vn -0.5154 -0.6844 0.5156 +vn -0.5719 -0.7685 0.2870 +vn -0.2870 -0.5719 0.7685 +vn -0.3064 -0.0783 0.9486 +vn -0.0787 -0.3066 0.9485 +vn -0.5855 -0.0754 0.8071 +vn -0.3098 -0.3089 0.8992 +vn -0.8072 -0.0757 0.5853 +vn -0.5718 -0.2866 0.7687 +vn -0.5156 -0.5154 0.6844 +vn -0.7685 -0.2870 0.5719 +vn -0.9486 -0.3064 0.0783 +vn -0.9485 -0.0787 0.3066 +vn -0.8071 -0.5855 0.0754 +vn -0.8992 -0.3098 0.3089 +vn -0.7687 -0.5718 0.2866 +vn -0.6844 -0.5156 0.5154 +usemtl Material.001 +s 1 +f 28/1/1 190/2/2 138/3/3 +f 163/4/4 136/5/5 192/6/6 +f 57/7/7 191/8/8 83/9/9 +f 111/10/10 56/11/11 2/12/12 +f 3/13/13 82/14/14 30/15/15 +f 4/16/16 6/17/17 1/18/18 +f 5/19/19 7/20/20 4/16/16 +f 17/21/21 8/22/22 5/19/19 +f 7/20/20 9/23/23 6/17/17 +f 7/20/20 11/24/24 10/25/25 +f 18/26/26 11/24/24 8/22/22 +f 12/27/27 14/28/28 2/12/12 +f 13/29/29 15/30/30 12/27/27 +f 25/31/31 16/32/32 13/29/29 +f 15/30/30 17/33/21 14/28/28 +f 15/30/30 19/34/33 18/35/26 +f 26/36/34 19/34/33 16/32/32 +f 20/37/35 22/38/36 3/13/13 +f 21/39/37 23/40/38 20/37/35 +f 9/23/23 24/41/39 21/39/37 +f 23/40/38 25/31/31 22/38/36 +f 23/40/38 27/42/40 26/36/34 +f 10/25/25 27/42/40 24/41/39 +f 11/24/24 19/43/33 27/44/40 +f 31/45/41 33/46/42 28/1/1 +f 32/47/43 34/48/44 31/45/41 +f 44/49/45 35/50/46 32/47/43 +f 34/48/44 36/51/47 33/46/42 +f 34/48/44 38/52/48 37/53/49 +f 45/54/50 38/52/48 35/50/46 +f 39/55/51 41/56/52 29/57/53 +f 40/58/54 42/59/55 39/55/51 +f 52/60/56 43/61/57 40/58/54 +f 42/59/55 44/62/45 41/56/52 +f 42/59/55 46/63/58 45/64/50 +f 53/65/59 46/63/58 43/61/57 +f 47/66/60 49/67/61 30/15/15 +f 48/68/62 50/69/63 47/66/60 +f 36/51/47 51/70/64 48/68/62 +f 50/69/63 52/60/56 49/67/61 +f 50/69/63 54/71/65 53/65/59 +f 37/53/49 54/71/65 51/70/64 +f 38/52/48 46/72/58 54/73/65 +f 58/74/66 60/75/67 55/76/68 +f 59/77/69 61/78/70 58/74/66 +f 71/79/71 62/80/72 59/77/69 +f 61/78/70 63/81/73 60/75/67 +f 61/78/70 65/82/74 64/83/75 +f 72/84/76 65/82/74 62/80/72 +f 66/85/77 68/86/78 56/11/11 +f 67/87/79 69/88/80 66/85/77 +f 79/89/81 70/90/82 67/87/79 +f 69/88/80 71/79/71 68/86/78 +f 69/88/80 73/91/83 72/84/76 +f 80/92/84 73/91/83 70/90/82 +f 74/93/85 76/94/86 57/7/7 +f 75/95/87 77/96/88 74/93/85 +f 63/81/73 78/97/89 75/95/87 +f 77/96/88 79/98/81 76/94/86 +f 77/96/88 81/99/90 80/100/84 +f 64/83/75 81/99/90 78/97/89 +f 65/82/74 73/101/83 81/102/90 +f 85/103/91 87/104/92 82/14/14 +f 86/105/93 88/106/94 85/103/91 +f 98/107/95 89/108/96 86/105/93 +f 88/106/94 90/109/97 87/104/92 +f 88/106/94 92/110/98 91/111/99 +f 99/112/100 92/110/98 89/108/96 +f 93/113/101 95/114/102 83/9/9 +f 94/115/103 96/116/104 93/113/101 +f 106/117/105 97/118/106 94/115/103 +f 96/116/104 98/107/95 95/114/102 +f 96/116/104 100/119/107 99/112/100 +f 107/120/108 100/119/107 97/118/106 +f 101/121/109 103/122/110 84/123/111 +f 102/124/112 104/125/113 101/121/109 +f 90/109/97 105/126/114 102/124/112 +f 104/125/113 106/127/105 103/122/110 +f 104/125/113 108/128/115 107/129/108 +f 91/111/99 108/128/115 105/126/114 +f 92/110/98 100/130/107 108/131/115 +f 112/132/116 114/133/117 109/134/118 +f 113/135/119 115/136/120 112/132/116 +f 125/137/121 116/138/122 113/135/119 +f 115/136/120 117/139/123 114/133/117 +f 115/136/120 119/140/124 118/141/125 +f 126/142/126 119/140/124 116/138/122 +f 120/143/127 122/144/128 110/145/129 +f 121/146/130 123/147/131 120/143/127 +f 133/148/132 124/149/133 121/146/130 +f 123/147/131 125/137/121 122/144/128 +f 123/147/131 127/150/134 126/142/126 +f 134/151/135 127/150/134 124/149/133 +f 128/152/136 130/153/137 111/10/10 +f 129/154/138 131/155/139 128/152/136 +f 117/156/123 132/157/140 129/154/138 +f 131/155/139 133/158/132 130/153/137 +f 131/155/139 135/159/141 134/160/135 +f 118/161/125 135/159/141 132/157/140 +f 119/140/124 127/162/134 135/163/141 +f 139/164/142 141/165/143 136/5/5 +f 140/166/144 142/167/145 139/164/142 +f 152/168/146 143/169/147 140/166/144 +f 142/167/145 144/170/148 141/165/143 +f 142/167/145 146/171/149 145/172/150 +f 153/173/151 146/171/149 143/169/147 +f 147/174/152 149/175/153 137/176/154 +f 148/177/155 150/178/156 147/174/152 +f 160/179/157 151/180/158 148/177/155 +f 150/178/156 152/168/146 149/175/153 +f 150/178/156 154/181/159 153/173/151 +f 161/182/160 154/181/159 151/180/158 +f 155/183/161 157/184/162 138/3/3 +f 156/185/163 158/186/164 155/183/161 +f 144/187/148 159/188/165 156/185/163 +f 158/186/164 160/189/157 157/184/162 +f 158/186/164 162/190/166 161/191/160 +f 145/192/150 162/190/166 159/188/165 +f 146/171/149 154/193/159 162/194/166 +f 166/195/167 168/196/168 163/4/4 +f 167/197/169 169/198/170 166/195/167 +f 179/199/171 170/200/172 167/197/169 +f 169/198/170 171/201/173 168/196/168 +f 169/198/170 173/202/174 172/203/175 +f 180/204/176 173/202/174 170/200/172 +f 174/205/177 176/206/178 164/207/179 +f 175/208/180 177/209/181 174/205/177 +f 187/210/182 178/211/183 175/208/180 +f 177/209/181 179/212/171 176/206/178 +f 177/209/181 181/213/184 180/214/176 +f 188/215/185 181/213/184 178/211/183 +f 182/216/186 184/217/187 165/218/188 +f 183/219/189 185/220/190 182/216/186 +f 171/221/173 186/222/191 183/219/189 +f 185/220/190 187/223/182 184/217/187 +f 185/220/190 189/224/192 188/225/185 +f 172/226/175 189/224/192 186/222/191 +f 173/202/174 181/227/184 189/228/192 +f 193/229/193 195/230/194 190/2/2 +f 194/231/195 196/232/196 193/229/193 +f 206/233/197 197/234/198 194/231/195 +f 196/232/196 198/235/199 195/230/194 +f 196/232/196 200/236/200 199/237/201 +f 207/238/202 200/236/200 197/234/198 +f 201/239/203 203/240/204 191/8/8 +f 202/241/205 204/242/206 201/239/203 +f 214/243/207 205/244/208 202/241/205 +f 204/242/206 206/245/197 203/240/204 +f 204/242/206 208/246/209 207/247/202 +f 215/248/210 208/246/209 205/244/208 +f 209/249/211 211/250/212 192/6/6 +f 210/251/213 212/252/214 209/249/211 +f 198/253/199 213/254/215 210/251/213 +f 212/252/214 214/255/207 211/250/212 +f 212/252/214 216/256/216 215/257/210 +f 199/258/201 216/256/216 213/254/215 +f 200/236/200 208/259/209 216/260/216 +f 190/2/2 155/183/161 138/3/3 +f 195/230/194 156/185/163 155/183/161 +f 198/235/199 144/187/148 156/185/163 +f 210/251/213 141/165/143 144/170/148 +f 209/249/211 136/5/5 141/165/143 +f 138/3/3 31/45/41 28/1/1 +f 157/184/162 32/47/43 31/45/41 +f 160/189/157 44/49/45 32/47/43 +f 148/177/155 41/56/52 44/62/45 +f 147/174/152 29/57/53 41/56/52 +f 30/15/15 20/37/35 3/13/13 +f 49/67/61 21/39/37 20/37/35 +f 52/60/56 9/23/23 21/39/37 +f 40/58/54 6/17/17 9/23/23 +f 39/55/51 1/18/18 6/17/17 +f 164/207/179 201/239/203 191/8/8 +f 176/206/178 202/241/205 201/239/203 +f 179/212/171 214/243/207 202/241/205 +f 167/197/169 211/250/212 214/255/207 +f 166/195/167 192/6/6 211/250/212 +f 83/9/9 74/93/85 57/7/7 +f 95/114/102 75/95/87 74/93/85 +f 98/107/95 63/81/73 75/95/87 +f 86/105/93 60/75/67 63/81/73 +f 85/103/91 55/76/68 60/75/67 +f 137/176/154 112/132/116 109/134/118 +f 149/175/153 113/135/119 112/132/116 +f 152/168/146 125/137/121 113/135/119 +f 140/166/144 122/144/128 125/137/121 +f 139/164/142 110/145/129 122/144/128 +f 165/218/188 66/85/77 56/11/11 +f 184/217/187 67/87/79 66/85/77 +f 187/223/182 79/89/81 67/87/79 +f 175/208/180 76/94/86 79/98/81 +f 174/205/177 57/7/7 76/94/86 +f 56/11/11 12/27/27 2/12/12 +f 68/86/78 13/29/29 12/27/27 +f 71/79/71 25/31/31 13/29/29 +f 59/77/69 22/38/36 25/31/31 +f 58/74/66 3/13/13 22/38/36 +f 84/123/111 193/229/193 190/2/2 +f 103/122/110 194/231/195 193/229/193 +f 106/127/105 206/233/197 194/231/195 +f 94/115/103 203/240/204 206/245/197 +f 93/113/101 191/8/8 203/240/204 +f 111/10/10 182/216/186 165/218/188 +f 130/153/137 183/219/189 182/216/186 +f 133/158/132 171/221/173 183/219/189 +f 121/146/130 168/196/168 171/201/173 +f 120/143/127 163/4/4 168/196/168 +f 2/12/12 128/152/136 111/10/10 +f 14/28/28 129/154/138 128/152/136 +f 17/33/21 117/156/123 129/154/138 +f 5/19/19 114/133/117 117/139/123 +f 4/16/16 109/134/118 114/133/117 +f 28/1/1 101/121/109 84/123/111 +f 33/46/42 102/124/112 101/121/109 +f 36/51/47 90/109/97 102/124/112 +f 48/68/62 87/104/92 90/109/97 +f 47/66/60 82/14/14 87/104/92 +f 109/134/118 29/57/53 137/176/154 +f 28/1/1 84/123/111 190/2/2 +f 163/4/4 110/145/129 136/5/5 +f 57/7/7 164/207/179 191/8/8 +f 111/10/10 165/218/188 56/11/11 +f 3/13/13 55/76/68 82/14/14 +f 4/16/16 7/20/20 6/17/17 +f 5/19/19 8/22/22 7/20/20 +f 17/21/21 18/26/26 8/22/22 +f 7/20/20 10/25/25 9/23/23 +f 7/20/20 8/22/22 11/24/24 +f 18/26/26 19/43/33 11/24/24 +f 12/27/27 15/30/30 14/28/28 +f 13/29/29 16/32/32 15/30/30 +f 25/31/31 26/36/34 16/32/32 +f 15/30/30 18/35/26 17/33/21 +f 15/30/30 16/32/32 19/34/33 +f 26/36/34 27/42/40 19/34/33 +f 20/37/35 23/40/38 22/38/36 +f 21/39/37 24/41/39 23/40/38 +f 9/23/23 10/25/25 24/41/39 +f 23/40/38 26/36/34 25/31/31 +f 23/40/38 24/41/39 27/42/40 +f 10/25/25 11/24/24 27/42/40 +f 31/45/41 34/48/44 33/46/42 +f 32/47/43 35/50/46 34/48/44 +f 44/49/45 45/54/50 35/50/46 +f 34/48/44 37/53/49 36/51/47 +f 34/48/44 35/50/46 38/52/48 +f 45/54/50 46/72/58 38/52/48 +f 39/55/51 42/59/55 41/56/52 +f 40/58/54 43/61/57 42/59/55 +f 52/60/56 53/65/59 43/61/57 +f 42/59/55 45/64/50 44/62/45 +f 42/59/55 43/61/57 46/63/58 +f 53/65/59 54/71/65 46/63/58 +f 47/66/60 50/69/63 49/67/61 +f 48/68/62 51/70/64 50/69/63 +f 36/51/47 37/53/49 51/70/64 +f 50/69/63 53/65/59 52/60/56 +f 50/69/63 51/70/64 54/71/65 +f 37/53/49 38/52/48 54/71/65 +f 58/74/66 61/78/70 60/75/67 +f 59/77/69 62/80/72 61/78/70 +f 71/79/71 72/84/76 62/80/72 +f 61/78/70 64/83/75 63/81/73 +f 61/78/70 62/80/72 65/82/74 +f 72/84/76 73/91/83 65/82/74 +f 66/85/77 69/88/80 68/86/78 +f 67/87/79 70/90/82 69/88/80 +f 79/89/81 80/92/84 70/90/82 +f 69/88/80 72/84/76 71/79/71 +f 69/88/80 70/90/82 73/91/83 +f 80/92/84 81/261/90 73/91/83 +f 74/93/85 77/96/88 76/94/86 +f 75/95/87 78/97/89 77/96/88 +f 63/81/73 64/83/75 78/97/89 +f 77/96/88 80/100/84 79/98/81 +f 77/96/88 78/97/89 81/99/90 +f 64/83/75 65/82/74 81/99/90 +f 85/103/91 88/106/94 87/104/92 +f 86/105/93 89/108/96 88/106/94 +f 98/107/95 99/112/100 89/108/96 +f 88/106/94 91/111/99 90/109/97 +f 88/106/94 89/108/96 92/110/98 +f 99/112/100 100/119/107 92/110/98 +f 93/113/101 96/116/104 95/114/102 +f 94/115/103 97/118/106 96/116/104 +f 106/117/105 107/120/108 97/118/106 +f 96/116/104 99/112/100 98/107/95 +f 96/116/104 97/118/106 100/119/107 +f 107/120/108 108/262/115 100/119/107 +f 101/121/109 104/125/113 103/122/110 +f 102/124/112 105/126/114 104/125/113 +f 90/109/97 91/111/99 105/126/114 +f 104/125/113 107/129/108 106/127/105 +f 104/125/113 105/126/114 108/128/115 +f 91/111/99 92/110/98 108/128/115 +f 112/132/116 115/136/120 114/133/117 +f 113/135/119 116/138/122 115/136/120 +f 125/137/121 126/142/126 116/138/122 +f 115/136/120 118/141/125 117/139/123 +f 115/136/120 116/138/122 119/140/124 +f 126/142/126 127/150/134 119/140/124 +f 120/143/127 123/147/131 122/144/128 +f 121/146/130 124/149/133 123/147/131 +f 133/148/132 134/151/135 124/149/133 +f 123/147/131 126/142/126 125/137/121 +f 123/147/131 124/149/133 127/150/134 +f 134/151/135 135/263/141 127/150/134 +f 128/152/136 131/155/139 130/153/137 +f 129/154/138 132/157/140 131/155/139 +f 117/156/123 118/161/125 132/157/140 +f 131/155/139 134/160/135 133/158/132 +f 131/155/139 132/157/140 135/159/141 +f 118/161/125 119/264/124 135/159/141 +f 139/164/142 142/167/145 141/165/143 +f 140/166/144 143/169/147 142/167/145 +f 152/168/146 153/173/151 143/169/147 +f 142/167/145 145/172/150 144/170/148 +f 142/167/145 143/169/147 146/171/149 +f 153/173/151 154/181/159 146/171/149 +f 147/174/152 150/178/156 149/175/153 +f 148/177/155 151/180/158 150/178/156 +f 160/179/157 161/182/160 151/180/158 +f 150/178/156 153/173/151 152/168/146 +f 150/178/156 151/180/158 154/181/159 +f 161/182/160 162/265/166 154/181/159 +f 155/183/161 158/186/164 157/184/162 +f 156/185/163 159/188/165 158/186/164 +f 144/187/148 145/192/150 159/188/165 +f 158/186/164 161/191/160 160/189/157 +f 158/186/164 159/188/165 162/190/166 +f 145/192/150 146/266/149 162/190/166 +f 166/195/167 169/198/170 168/196/168 +f 167/197/169 170/200/172 169/198/170 +f 179/199/171 180/204/176 170/200/172 +f 169/198/170 172/203/175 171/201/173 +f 169/198/170 170/200/172 173/202/174 +f 180/204/176 181/227/184 173/202/174 +f 174/205/177 177/209/181 176/206/178 +f 175/208/180 178/211/183 177/209/181 +f 187/210/182 188/215/185 178/211/183 +f 177/209/181 180/214/176 179/212/171 +f 177/209/181 178/211/183 181/213/184 +f 188/215/185 189/267/192 181/213/184 +f 182/216/186 185/220/190 184/217/187 +f 183/219/189 186/222/191 185/220/190 +f 171/221/173 172/226/175 186/222/191 +f 185/220/190 188/225/185 187/223/182 +f 185/220/190 186/222/191 189/224/192 +f 172/226/175 173/268/174 189/224/192 +f 193/229/193 196/232/196 195/230/194 +f 194/231/195 197/234/198 196/232/196 +f 206/233/197 207/238/202 197/234/198 +f 196/232/196 199/237/201 198/235/199 +f 196/232/196 197/234/198 200/236/200 +f 207/238/202 208/259/209 200/236/200 +f 201/239/203 204/242/206 203/240/204 +f 202/241/205 205/244/208 204/242/206 +f 214/243/207 215/248/210 205/244/208 +f 204/242/206 207/247/202 206/245/197 +f 204/242/206 205/244/208 208/246/209 +f 215/248/210 216/269/216 208/246/209 +f 209/249/211 212/252/214 211/250/212 +f 210/251/213 213/254/215 212/252/214 +f 198/253/199 199/258/201 213/254/215 +f 212/252/214 215/257/210 214/255/207 +f 212/252/214 213/254/215 216/256/216 +f 199/258/201 200/270/200 216/256/216 +f 190/2/2 195/230/194 155/183/161 +f 195/230/194 198/235/199 156/185/163 +f 198/235/199 210/271/213 144/187/148 +f 210/251/213 209/249/211 141/165/143 +f 209/249/211 192/6/6 136/5/5 +f 138/3/3 157/184/162 31/45/41 +f 157/184/162 160/189/157 32/47/43 +f 160/189/157 148/272/155 44/49/45 +f 148/177/155 147/174/152 41/56/52 +f 147/174/152 137/176/154 29/57/53 +f 30/15/15 49/67/61 20/37/35 +f 49/67/61 52/60/56 21/39/37 +f 52/60/56 40/58/54 9/23/23 +f 40/58/54 39/55/51 6/17/17 +f 39/55/51 29/57/53 1/18/18 +f 164/207/179 176/206/178 201/239/203 +f 176/206/178 179/212/171 202/241/205 +f 179/212/171 167/273/169 214/243/207 +f 167/197/169 166/195/167 211/250/212 +f 166/195/167 163/4/4 192/6/6 +f 83/9/9 95/114/102 74/93/85 +f 95/114/102 98/107/95 75/95/87 +f 98/107/95 86/105/93 63/81/73 +f 86/105/93 85/103/91 60/75/67 +f 85/103/91 82/14/14 55/76/68 +f 137/176/154 149/175/153 112/132/116 +f 149/175/153 152/168/146 113/135/119 +f 152/168/146 140/166/144 125/137/121 +f 140/166/144 139/164/142 122/144/128 +f 139/164/142 136/5/5 110/145/129 +f 165/218/188 184/217/187 66/85/77 +f 184/217/187 187/223/182 67/87/79 +f 187/223/182 175/274/180 79/89/81 +f 175/208/180 174/205/177 76/94/86 +f 174/205/177 164/207/179 57/7/7 +f 56/11/11 68/86/78 12/27/27 +f 68/86/78 71/79/71 13/29/29 +f 71/79/71 59/77/69 25/31/31 +f 59/77/69 58/74/66 22/38/36 +f 58/74/66 55/76/68 3/13/13 +f 84/123/111 103/122/110 193/229/193 +f 103/122/110 106/127/105 194/231/195 +f 106/127/105 94/275/103 206/233/197 +f 94/115/103 93/113/101 203/240/204 +f 93/113/101 83/9/9 191/8/8 +f 111/10/10 130/153/137 182/216/186 +f 130/153/137 133/158/132 183/219/189 +f 133/158/132 121/276/130 171/221/173 +f 121/146/130 120/143/127 168/196/168 +f 120/143/127 110/145/129 163/4/4 +f 2/12/12 14/28/28 128/152/136 +f 14/28/28 17/33/21 129/154/138 +f 17/33/21 5/277/19 117/156/123 +f 5/19/19 4/16/16 114/133/117 +f 4/16/16 1/18/18 109/134/118 +f 28/1/1 33/46/42 101/121/109 +f 33/46/42 36/51/47 102/124/112 +f 36/51/47 48/68/62 90/109/97 +f 48/68/62 47/66/60 87/104/92 +f 47/66/60 30/15/15 82/14/14 +f 109/134/118 1/18/18 29/57/53 diff --git a/src/app.rs b/src/app.rs index dcf10b5..f6064a4 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,6 +1,3 @@ -use eframe::{egui, egui_wgpu}; -use std::sync::Arc; - use crate::connection::ConnectionManager; use crate::recording::Recorder; use crate::theme::{ONE_DARK_PRO, apply_fonts, apply_theme}; @@ -16,6 +13,8 @@ use crate::{ draw_scene_panel, draw_stats_panel, }, }; +use eframe::{egui, egui_wgpu}; +use std::sync::Arc; const DATA_LOG_EVERY_FRAMES: u64 = 30; @@ -54,6 +53,7 @@ impl EskinDesktopApp { .callback_resources .insert(BackgroundRenderResources::new( &wgpu_state.device, + &wgpu_state.queue, &wgpu_state.target_format, MATRIX_ROWS, MATRIX_COLS, diff --git a/src/main.rs b/src/main.rs index 0628942..b25aaa0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,15 @@ mod app; mod connection; mod matrix; +mod model; mod recording; mod render; +mod resources; mod serial_core; +mod texture; mod theme; mod ui; mod utils; -mod model; use app::EskinDesktopApp; use eframe::egui; diff --git a/src/model.rs b/src/model.rs index 2c263e3..34ca115 100644 --- a/src/model.rs +++ b/src/model.rs @@ -1,9 +1,7 @@ -use eframe::{ - egui, - egui_wgpu::{self, wgpu}, - wgpu::util::DeviceExt, -}; +use eframe::egui_wgpu::wgpu; +use std::ops::Range; +use crate::texture; pub trait Vertex { fn desc<'a>() -> wgpu::VertexBufferLayout<'a>; } @@ -12,4 +10,137 @@ pub trait Vertex { #[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] pub struct ModelVertex { pub position: [f32; 3], -} \ No newline at end of file + pub tex_coords: [f32; 2], + pub normal: [f32; 3], +} + +impl Vertex for ModelVertex { + fn desc<'a>() -> wgpu::VertexBufferLayout<'a> { + use core::mem; + wgpu::VertexBufferLayout { + array_stride: mem::size_of::() as wgpu::BufferAddress, + step_mode: wgpu::VertexStepMode::Vertex, + attributes: &[ + wgpu::VertexAttribute { + offset: 0, + shader_location: 0, + format: wgpu::VertexFormat::Float32x3, + }, + wgpu::VertexAttribute { + offset: mem::size_of::<[f32; 3]>() as wgpu::BufferAddress, + shader_location: 1, + format: wgpu::VertexFormat::Float32x2, + }, + wgpu::VertexAttribute { + offset: mem::size_of::<[f32; 5]>() as wgpu::BufferAddress, + shader_location: 2, + format: wgpu::VertexFormat::Float32x3, + }, + ], + } + } +} + +pub struct Instance { + position: glam::Vec3, + rotation: glam::Quat, +} + +impl Instance { + pub fn new(position: glam::Vec3, rotation: glam::Quat) -> Self { + Self { position, rotation } + } + + pub fn to_raw(&self) -> InstanceRaw { + InstanceRaw { + model: (glam::Mat4::from_translation(self.position) + * glam::Mat4::from_quat(self.rotation)) + .to_cols_array_2d(), + } + } +} + +#[repr(C)] +#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] +pub struct InstanceRaw { + #[allow(dead_code)] + model: [[f32; 4]; 4], +} + +impl InstanceRaw { + pub fn desc<'a>() -> wgpu::VertexBufferLayout<'a> { + use core::mem; + wgpu::VertexBufferLayout { + array_stride: mem::size_of::() as wgpu::BufferAddress, + // We need to switch from using a step mode of Vertex to Instance + // This means that our shaders will only change to use the next + // instance when the shader starts processing a new instance + step_mode: wgpu::VertexStepMode::Instance, + attributes: &[ + wgpu::VertexAttribute { + offset: 0, + // While our vertex shader only uses locations 0, and 1 now, in later tutorials we'll + // be using 2, 3, and 4, for Vertex. We'll start at slot 5 not conflict with them later + shader_location: 5, + format: wgpu::VertexFormat::Float32x4, + }, + // A mat4 takes up 4 vertex slots as it is technically 4 vec4s. We need to define a slot + // for each vec4. We don't have to do this in code though. + wgpu::VertexAttribute { + offset: mem::size_of::<[f32; 4]>() as wgpu::BufferAddress, + shader_location: 6, + format: wgpu::VertexFormat::Float32x4, + }, + wgpu::VertexAttribute { + offset: mem::size_of::<[f32; 8]>() as wgpu::BufferAddress, + shader_location: 7, + format: wgpu::VertexFormat::Float32x4, + }, + wgpu::VertexAttribute { + offset: mem::size_of::<[f32; 12]>() as wgpu::BufferAddress, + shader_location: 8, + format: wgpu::VertexFormat::Float32x4, + }, + ], + } + } +} + +pub struct Model { + pub meshes: Vec, + pub materials: Vec, +} + +pub struct Material { + pub name: String, + pub diffuse_texture: texture::Texture, + pub bind_group: wgpu::BindGroup, +} + +pub struct Mesh { + pub name: String, + pub vertex_buffer: wgpu::Buffer, + pub index_buffer: wgpu::Buffer, + pub num_elements: u32, + pub material: usize, +} + +pub trait DrawModel<'a> { + fn draw_mesh(&mut self, mesh: &'a Mesh); + fn draw_mesh_instanced(&mut self, mesh: &'a Mesh, instances: Range); +} + +impl<'a, 'b> DrawModel<'b> for wgpu::RenderPass<'a> +where + 'b: 'a, +{ + fn draw_mesh(&mut self, mesh: &'b Mesh) { + self.draw_mesh_instanced(mesh, 0..1); + } + + fn draw_mesh_instanced(&mut self, mesh: &'b Mesh, instances: Range) { + self.set_vertex_buffer(0, mesh.vertex_buffer.slice(..)); + self.set_index_buffer(mesh.index_buffer.slice(..), wgpu::IndexFormat::Uint32); + self.draw_indexed(0..mesh.num_elements, 0, instances); + } +} diff --git a/src/render.rs b/src/render.rs index 1f2b7ef..5663003 100644 --- a/src/render.rs +++ b/src/render.rs @@ -1,11 +1,14 @@ +use crate::{ + matrix::{MatrixLayout, build_view_projection, glyph_world_position}, + model::{Instance, InstanceRaw, Model, ModelVertex, Vertex}, + resources, +}; use eframe::{ egui, egui_wgpu::{self, wgpu}, wgpu::util::DeviceExt, }; -use crate::matrix::{MatrixLayout, build_view_projection, glyph_world_position}; - pub const PRESSURE_CELL_COUNT: usize = (crate::matrix::MATRIX_ROWS * crate::matrix::MATRIX_COLS) as usize; pub type PressureFrame = [[f32; 2]; PRESSURE_CELL_COUNT]; @@ -65,6 +68,9 @@ pub struct BackgroundRenderResources { background_pipeline: wgpu::RenderPipeline, glyph_pipeline: wgpu::RenderPipeline, dot_pipeline: wgpu::RenderPipeline, + model_pipeline: wgpu::RenderPipeline, + model: Option, + model_instance_buffer: wgpu::Buffer, glyph_vertex_buffer: wgpu::Buffer, glyph_instance_buffer: wgpu::Buffer, glyph_instances: Vec, @@ -74,6 +80,7 @@ pub struct BackgroundRenderResources { impl BackgroundRenderResources { pub fn new( device: &wgpu::Device, + _queue: &wgpu::Queue, target_format: &wgpu::TextureFormat, rows: u32, cols: u32, @@ -125,18 +132,72 @@ impl BackgroundRenderResources { // source: wgpu::ShaderSource::Wgsl(include_str!("../static/wgsl/shader.wgsl").into()), // }); + let texture_bind_group_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("model_texture_bind_group_layout"), + entries: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + view_dimension: wgpu::TextureViewDimension::D2, + multisampled: false, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), + count: None, + }, + ], + }); + let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("Pressure Matrix Pipeline Layout"), bind_group_layouts: &[Some(&uniform_bind_group_layout)], immediate_size: 0, }); + let model_pipeline_layout = + device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("Hand Model Pipeline Layout"), + bind_group_layouts: &[ + Some(&uniform_bind_group_layout), + Some(&texture_bind_group_layout), + ], + immediate_size: 0, + }); let background_pipeline = create_background_pipeline(device, target_format, &shader, &pipeline_layout); let glyph_pipeline = create_glyph_pipeline(device, target_format, &shader, &pipeline_layout); - let dot_pipeline = - create_dot_pipeline(device, target_format, &shader, &pipeline_layout); + let dot_pipeline = create_dot_pipeline(device, target_format, &shader, &pipeline_layout); + + let model_pipeline = + create_model_pipeline(device, target_format, &shader, &model_pipeline_layout); + + let model = + match resources::load_model("cube.obj", device, _queue, &texture_bind_group_layout) { + Ok(model) => Some(model), + Err(err) => { + log::warn!("failed to load cube.obj: {err:#}"); + None + } + }; + + let model_instance = Instance::new( + glam::Vec3::new(0.0, -2.0, 12.0), + glam::Quat::from_rotation_y(0.65) * glam::Quat::from_rotation_x(-0.35), + ) + .to_raw(); + let model_instance_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("Hand Model Instance Buffer"), + contents: bytemuck::cast_slice(&[model_instance]), + usage: wgpu::BufferUsages::VERTEX, + }); let glyph_vertices = [ GlyphVertex { @@ -172,6 +233,9 @@ impl BackgroundRenderResources { background_pipeline, glyph_pipeline, dot_pipeline, + model_pipeline, + model, + model_instance_buffer, glyph_vertex_buffer, glyph_instance_buffer, glyph_instances, @@ -217,6 +281,20 @@ impl BackgroundRenderResources { render_pass.set_pipeline(&self.background_pipeline); render_pass.draw(0..3, 0..1); + if let Some(model) = &self.model { + render_pass.set_pipeline(&self.model_pipeline); + render_pass.set_vertex_buffer(1, self.model_instance_buffer.slice(..)); + for mesh in &model.meshes { + if let Some(material) = model.materials.get(mesh.material) { + render_pass.set_bind_group(1, &material.bind_group, &[]); + } + render_pass.set_vertex_buffer(0, mesh.vertex_buffer.slice(..)); + render_pass + .set_index_buffer(mesh.index_buffer.slice(..), wgpu::IndexFormat::Uint32); + render_pass.draw_indexed(0..mesh.num_elements, 0, 0..1); + } + } + // let marker_pipeline = match self.marker_mode { // MarkerMode::Number => &self.glyph_pipeline, // MarkerMode::Dot => &self.dot_pipeline, @@ -296,6 +374,54 @@ fn create_glyph_pipeline( }) } +fn create_model_pipeline( + device: &wgpu::Device, + target_format: &wgpu::TextureFormat, + shader: &wgpu::ShaderModule, + layout: &wgpu::PipelineLayout, +) -> wgpu::RenderPipeline { + device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("Hand Model Pipeline"), + layout: Some(layout), + vertex: wgpu::VertexState { + module: shader, + entry_point: Some("vs_model"), + compilation_options: Default::default(), + buffers: &[ModelVertex::desc(), InstanceRaw::desc()], + }, + fragment: Some(wgpu::FragmentState { + module: shader, + entry_point: Some("fs_model"), + compilation_options: Default::default(), + targets: &[Some(wgpu::ColorTargetState { + format: *target_format, + blend: Some(wgpu::BlendState { + color: wgpu::BlendComponent::REPLACE, + alpha: wgpu::BlendComponent::REPLACE, + }), + write_mask: wgpu::ColorWrites::ALL, + })], + }), + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + strip_index_format: None, + front_face: wgpu::FrontFace::Ccw, + cull_mode: None, + polygon_mode: wgpu::PolygonMode::Fill, + unclipped_depth: false, + conservative: false, + }, + depth_stencil: None, + multisample: wgpu::MultisampleState { + count: 1, + mask: !0, + alpha_to_coverage_enabled: false, + }, + multiview_mask: None, + cache: None, + }) +} + fn create_dot_pipeline( device: &wgpu::Device, target_format: &wgpu::TextureFormat, diff --git a/src/resources.rs b/src/resources.rs new file mode 100644 index 0000000..ff0e4b3 --- /dev/null +++ b/src/resources.rs @@ -0,0 +1,128 @@ +use crate::{model, texture}; +use eframe::wgpu; +use eframe::wgpu::util::DeviceExt; +use std::path::{Path, PathBuf}; + +fn resource_path(file_name: &str) -> PathBuf { + Path::new(env!("RESOURCE_DIR")).join(file_name) +} + +pub fn load_string(file_name: &str) -> anyhow::Result { + Ok(std::fs::read_to_string(resource_path(file_name))?) +} + +pub fn load_binary(file_name: &str) -> anyhow::Result> { + Ok(std::fs::read(resource_path(file_name))?) +} + +pub fn load_texture( + file_name: &str, + device: &wgpu::Device, + queue: &wgpu::Queue, +) -> anyhow::Result { + let data = load_binary(file_name)?; + texture::Texture::from_bytes(device, queue, &data, file_name) +} + +pub fn load_model( + file_name: &str, + device: &wgpu::Device, + queue: &wgpu::Queue, + texture_bind_group_layout: &wgpu::BindGroupLayout, +) -> anyhow::Result { + let path = resource_path(file_name); + let (models, obj_materials) = tobj::load_obj( + &path, + &tobj::LoadOptions { + single_index: true, + triangulate: true, + ..Default::default() + }, + )?; + + let mut materials = Vec::new(); + for material in obj_materials? { + let diffuse_texture = match material.diffuse_texture.as_deref() { + Some(texture_path) => load_texture(texture_path, device, queue)?, + None => texture::Texture::from_rgba8( + device, + queue, + &[255, 255, 255, 255], + 1, + 1, + &material.name, + )?, + }; + + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some(&format!("{} Texture Bind Group", material.name)), + layout: texture_bind_group_layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureView(&diffuse_texture.view), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::Sampler(&diffuse_texture.sampler), + }, + ], + }); + + materials.push(model::Material { + name: material.name, + diffuse_texture, + bind_group, + }); + } + + let meshes = models + .into_iter() + .map(|m| { + let vertices = (0..m.mesh.positions.len() / 3) + .map(|i| model::ModelVertex { + position: [ + m.mesh.positions[i * 3], + m.mesh.positions[i * 3 + 1], + m.mesh.positions[i * 3 + 2], + ], + tex_coords: if m.mesh.texcoords.len() >= i * 2 + 2 { + [m.mesh.texcoords[i * 2], m.mesh.texcoords[i * 2 + 1]] + } else { + [0.0, 0.0] + }, + normal: if m.mesh.normals.len() >= i * 3 + 3 { + [ + m.mesh.normals[i * 3], + m.mesh.normals[i * 3 + 1], + m.mesh.normals[i * 3 + 2], + ] + } else { + [0.0, 1.0, 0.0] + }, + }) + .collect::>(); + + let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some(&format!("{} Vertex Buffer", m.name)), + contents: bytemuck::cast_slice(&vertices), + usage: wgpu::BufferUsages::VERTEX, + }); + let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some(&format!("{} Index Buffer", m.name)), + contents: bytemuck::cast_slice(&m.mesh.indices), + usage: wgpu::BufferUsages::INDEX, + }); + + model::Mesh { + name: m.name, + vertex_buffer, + index_buffer, + num_elements: m.mesh.indices.len() as u32, + material: m.mesh.material_id.unwrap_or(0), + } + }) + .collect::>(); + + Ok(model::Model { meshes, materials }) +} diff --git a/src/texture.rs b/src/texture.rs index 6570a7a..7d4492c 100644 --- a/src/texture.rs +++ b/src/texture.rs @@ -1,8 +1,12 @@ -use anyhow::*; -use eframe::egui_wgpu::{self, wgpu}; -use image::GenericImageView; +#![allow(dead_code)] -#[allow(dead_code)] +use anyhow::*; +use eframe::{ + egui, + egui_wgpu::{self, wgpu}, + wgpu::util::DeviceExt, +}; +use image::GenericImageView; pub struct Texture { pub texture: wgpu::Texture, pub view: wgpu::TextureView, @@ -10,6 +14,51 @@ pub struct Texture { } impl Texture { + pub const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; + + pub fn create_depth_texture( + device: &wgpu::Device, + config: &wgpu::SurfaceConfiguration, + label: &str, + ) -> Self { + let size = wgpu::Extent3d { + width: config.width, + height: config.height, + depth_or_array_layers: 1, + }; + let desc = wgpu::TextureDescriptor { + label: Some(label), + size, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: Self::DEPTH_FORMAT, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING, + view_formats: &[], + }; + let texture = device.create_texture(&desc); + let view = texture.create_view(&wgpu::TextureViewDescriptor::default()); + let sampler = device.create_sampler(&wgpu::SamplerDescriptor { + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + mag_filter: wgpu::FilterMode::Linear, + min_filter: wgpu::FilterMode::Linear, + mipmap_filter: wgpu::MipmapFilterMode::Nearest, + compare: Some(wgpu::CompareFunction::LessEqual), + lod_min_clamp: 0.0, + lod_max_clamp: 200.0, + ..Default::default() + }); + + Self { + texture, + view, + sampler, + } + } + + #[allow(dead_code)] pub fn from_bytes( device: &wgpu::Device, queue: &wgpu::Queue, @@ -26,8 +75,8 @@ impl Texture { img: &image::DynamicImage, label: Option<&str>, ) -> Result { - let rgba = img.to_rgba8(); let dimensions = img.dimensions(); + let rgba = img.to_rgba8(); let size = wgpu::Extent3d { width: dimensions.0, @@ -78,4 +127,62 @@ impl Texture { sampler, }) } + + pub fn from_rgba8( + device: &wgpu::Device, + queue: &wgpu::Queue, + rgba: &[u8], + width: u32, + height: u32, + label: &str, + ) -> Result { + let size = wgpu::Extent3d { + width, + height, + depth_or_array_layers: 1, + }; + let texture = device.create_texture(&wgpu::TextureDescriptor { + label: Some(label), + size, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Rgba8UnormSrgb, + usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, + view_formats: &[], + }); + + queue.write_texture( + wgpu::TexelCopyTextureInfo { + aspect: wgpu::TextureAspect::All, + texture: &texture, + mip_level: 0, + origin: wgpu::Origin3d::ZERO, + }, + rgba, + wgpu::TexelCopyBufferLayout { + offset: 0, + bytes_per_row: Some(4 * width), + rows_per_image: Some(height), + }, + size, + ); + + let view = texture.create_view(&wgpu::TextureViewDescriptor::default()); + let sampler = device.create_sampler(&wgpu::SamplerDescriptor { + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + mag_filter: wgpu::FilterMode::Linear, + min_filter: wgpu::FilterMode::Nearest, + mipmap_filter: wgpu::MipmapFilterMode::Nearest, + ..Default::default() + }); + + Ok(Self { + texture, + view, + sampler, + }) + } } diff --git a/static/wgsl/shader.wgsl b/static/wgsl/shader.wgsl index 180f4e5..7f20ec8 100644 --- a/static/wgsl/shader.wgsl +++ b/static/wgsl/shader.wgsl @@ -8,6 +8,12 @@ struct MatrixUniform { @group(0) @binding(0) var u: MatrixUniform; +@group(1) @binding(0) +var model_texture: texture_2d; + +@group(1) @binding(1) +var model_sampler: sampler; + fn saturate(value: f32) -> f32 { return clamp(value, 0.0, 1.0); } @@ -305,4 +311,48 @@ fn fs_dot(in: DotVertexOutput) -> @location(0) vec4f { let alpha = max(core, glow); return vec4f(color, alpha); -} \ No newline at end of file +} + + +// model +struct ModelVertexInput { + @location(0) position: vec3f, + @location(1) tex_coords: vec2f, + @location(2) normal: vec3f, + @location(5) model_0: vec4f, + @location(6) model_1: vec4f, + @location(7) model_2: vec4f, + @location(8) model_3: vec4f, +} + +struct ModelVertexOutput { + @builtin(position) clip_position: vec4f, + @location(0) world_normal: vec3f, + @location(1) world_position: vec3f, + @location(2) tex_coords: vec2f, +} + +@vertex +fn vs_model(vertex: ModelVertexInput) -> ModelVertexOutput { + let model = mat4x4f(vertex.model_0, vertex.model_1, vertex.model_2, vertex.model_3); + let world_position = model * vec4f(vertex.position, 1.0); + let normal_matrix = mat3x3f(model[0].xyz, model[1].xyz, model[2].xyz); + + var out: ModelVertexOutput; + out.clip_position = u.view_proj * world_position; + out.world_position = world_position.xyz; + out.world_normal = normalize(normal_matrix * vertex.normal); + out.tex_coords = vec2f(vertex.tex_coords.x, 1.0 - vertex.tex_coords.y); + return out; +} + +@fragment +fn fs_model(in: ModelVertexOutput) -> @location(0) vec4f { + let light_dir = normalize(vec3f(-0.35, 0.85, 0.45)); + let normal = normalize(in.world_normal); + let diffuse = max(dot(normal, light_dir), 0.0); + let rim = pow(1.0 - saturate(abs(normal.y)), 2.0) * 0.16; + let base = textureSample(model_texture, model_sampler, in.tex_coords).rgb; + let color = base * (0.28 + diffuse * 0.72) + vec3f(0.14, 0.24, 0.32) * rim; + return vec4f(color, 1.0); +}