diff --git a/crates/bevy_mikktspace/Cargo.toml b/crates/bevy_mikktspace/Cargo.toml index e5471e7bc3451..d882f9599562c 100644 --- a/crates/bevy_mikktspace/Cargo.toml +++ b/crates/bevy_mikktspace/Cargo.toml @@ -2,7 +2,11 @@ name = "bevy_mikktspace" version = "0.12.0-dev" edition = "2021" -authors = ["Benjamin Wasty ", "David Harvey-Macaulay ", "Layl Bongers "] +authors = [ + "Benjamin Wasty ", + "David Harvey-Macaulay ", + "Layl Bongers ", +] description = "Mikkelsen tangent space algorithm" documentation = "https://docs.rs/bevy" homepage = "https://bevyengine.org" @@ -12,6 +16,10 @@ keywords = ["bevy", "3D", "graphics", "algorithm", "tangent"] [dependencies] glam = "0.24" +bitflags = "2.3" + +[dev-dependencies] +bytemuck = { version = "1.13", features = ["derive"] } [[example]] -name = "generate" +name = "cube_tangents" diff --git a/crates/bevy_mikktspace/README.md b/crates/bevy_mikktspace/README.md index b5f886ce7abf5..ea349e5f5fee9 100644 --- a/crates/bevy_mikktspace/README.md +++ b/crates/bevy_mikktspace/README.md @@ -8,12 +8,12 @@ Requires at least Rust 1.52.1. ## Examples -### generate +### cube_tangents Demonstrates generating tangents for a cube with 4 triangular faces per side. ```sh -cargo run --example generate +cargo run --example cube_tangents ``` ## License agreement diff --git a/crates/bevy_mikktspace/data/cube.bin b/crates/bevy_mikktspace/data/cube.bin new file mode 100644 index 0000000000000..17fe907dcdb39 Binary files /dev/null and b/crates/bevy_mikktspace/data/cube.bin differ diff --git a/crates/bevy_mikktspace/examples/cube.obj b/crates/bevy_mikktspace/data/cube.obj similarity index 100% rename from crates/bevy_mikktspace/examples/cube.obj rename to crates/bevy_mikktspace/data/cube.obj diff --git a/crates/bevy_mikktspace/data/suzanne_bad.bin b/crates/bevy_mikktspace/data/suzanne_bad.bin new file mode 100644 index 0000000000000..587109b5a0358 Binary files /dev/null and b/crates/bevy_mikktspace/data/suzanne_bad.bin differ diff --git a/crates/bevy_mikktspace/data/suzanne_bad.obj b/crates/bevy_mikktspace/data/suzanne_bad.obj new file mode 100644 index 0000000000000..f22fa95611d90 --- /dev/null +++ b/crates/bevy_mikktspace/data/suzanne_bad.obj @@ -0,0 +1,2036 @@ +# Blender 3.6.0 +# www.blender.org +o Suzanne +v 0.000000 0.164062 0.326615 +v 0.000000 0.164062 0.326615 +v 0.000000 0.093750 0.326615 +v 0.000000 0.093750 0.326615 +v 0.000000 0.054688 0.326615 +v 0.000000 0.054688 0.326615 +v 0.000000 -0.023438 0.326615 +v 0.000000 -0.023438 0.326615 +v 0.000000 0.031250 0.326615 +v 0.000000 0.031250 0.326615 +v 0.000000 0.132812 0.326615 +v 0.000000 0.132812 0.326615 +v 0.000000 0.164062 0.326615 +v 0.000000 0.164062 0.326615 +v 0.000000 0.093750 0.326615 +v 0.000000 0.093750 0.326615 +v 0.000000 0.054688 0.326615 +v 0.000000 0.054688 0.326615 +v 0.000000 0.242188 0.326615 +v 0.000000 0.242188 0.326615 +v 0.000000 0.242188 0.326615 +v 0.000000 0.242188 0.326615 +v 0.000000 0.242188 0.326615 +v 0.000000 0.242188 0.326615 +v 0.000000 0.328125 0.326615 +v 0.000000 0.328125 0.326615 +v 0.000000 0.390625 0.326615 +v 0.000000 0.390625 0.326615 +v 0.000000 0.437500 0.326615 +v 0.000000 0.437500 0.326615 +v 0.000000 0.515625 0.326615 +v 0.000000 0.515625 0.326615 +v 0.000000 0.453125 0.326615 +v 0.000000 0.453125 0.326615 +v 0.000000 0.359375 0.326615 +v 0.000000 0.359375 0.326615 +v 0.000000 0.328125 0.326615 +v 0.000000 0.328125 0.326615 +v 0.000000 0.390625 0.326615 +v 0.000000 0.390625 0.326615 +v 0.000000 0.437500 0.326615 +v 0.000000 0.437500 0.326615 +v 0.000000 0.242188 0.326615 +v 0.000000 0.242188 0.326615 +v 0.000000 0.242188 0.326615 +v 0.000000 0.242188 0.326615 +v 0.000000 0.242188 0.326615 +v 0.000000 0.242188 0.326615 +v 0.000000 0.242188 0.326615 +v 0.000000 0.242188 0.326615 +v 0.000000 0.335938 0.326615 +v 0.000000 0.335938 0.326615 +v 0.000000 0.375000 0.326615 +v 0.000000 0.375000 0.326615 +v 0.000000 0.335938 0.326615 +v 0.000000 0.335938 0.326615 +v 0.000000 0.242188 0.326615 +v 0.000000 0.242188 0.326615 +v 0.000000 0.156250 0.326615 +v 0.000000 0.156250 0.326615 +v 0.000000 0.242188 0.326615 +v 0.000000 0.242188 0.326615 +v 0.000000 0.117188 0.326615 +v 0.000000 0.117188 0.326615 +v 0.000000 0.156250 0.326615 +v 0.000000 0.156250 0.326615 +v 0.000000 0.429688 0.326615 +v 0.000000 0.351562 0.326615 +v 0.000000 -0.679688 0.326615 +v 0.000000 -0.320312 0.326615 +v 0.000000 -0.187500 0.326615 +v 0.000000 -0.773438 0.326615 +v 0.000000 0.406250 0.326615 +v 0.000000 0.570312 0.326615 +v 0.000000 0.898438 0.326615 +v 0.000000 0.562500 0.326615 +v 0.000000 0.070312 0.326615 +v 0.000000 -0.382812 0.326615 +v 0.000000 -0.187500 0.326615 +v 0.000000 -0.187500 0.326615 +v 0.000000 -0.437500 0.326615 +v 0.000000 -0.437500 0.326615 +v 0.000000 -0.695312 0.326615 +v 0.000000 -0.695312 0.326615 +v 0.000000 -0.890625 0.326615 +v 0.000000 -0.890625 0.326615 +v 0.000000 -0.945312 0.326615 +v 0.000000 -0.945312 0.326615 +v 0.000000 -0.968750 0.326615 +v 0.000000 -0.968750 0.326615 +v 0.000000 -0.984375 0.326615 +v 0.000000 -0.140625 0.326615 +v 0.000000 -0.140625 0.326615 +v 0.000000 -0.039062 0.326615 +v 0.000000 -0.039062 0.326615 +v 0.000000 0.148438 0.326615 +v 0.000000 0.148438 0.326615 +v 0.000000 0.429688 0.326615 +v 0.000000 0.429688 0.326615 +v 0.000000 0.484375 0.326615 +v 0.000000 0.484375 0.326615 +v 0.000000 0.601562 0.326615 +v 0.000000 0.601562 0.326615 +v 0.000000 0.757812 0.326615 +v 0.000000 0.757812 0.326615 +v 0.000000 0.718750 0.326615 +v 0.000000 0.718750 0.326615 +v 0.000000 0.492188 0.326615 +v 0.000000 0.492188 0.326615 +v 0.000000 0.414062 0.326615 +v 0.000000 0.414062 0.326615 +v 0.000000 0.304688 0.326615 +v 0.000000 0.304688 0.326615 +v 0.000000 0.093750 0.326615 +v 0.000000 0.093750 0.326615 +v 0.000000 0.015625 0.326615 +v 0.000000 0.015625 0.326615 +v 0.000000 0.062500 0.326615 +v 0.000000 0.062500 0.326615 +v 0.000000 0.187500 0.326615 +v 0.000000 0.187500 0.326615 +v 0.000000 0.296875 0.326615 +v 0.000000 0.296875 0.326615 +v 0.000000 0.375000 0.326615 +v 0.000000 0.375000 0.326615 +v 0.000000 0.437500 0.326615 +v 0.000000 0.437500 0.326615 +v 0.000000 0.468750 0.326615 +v 0.000000 0.468750 0.326615 +v 0.000000 -0.765625 0.326615 +v 0.000000 -0.718750 0.326615 +v 0.000000 -0.718750 0.326615 +v 0.000000 -0.835938 0.326615 +v 0.000000 -0.835938 0.326615 +v 0.000000 -0.882812 0.326615 +v 0.000000 -0.882812 0.326615 +v 0.000000 -0.890625 0.326615 +v 0.000000 -0.195312 0.326615 +v 0.000000 -0.140625 0.326615 +v 0.000000 -0.148438 0.326615 +v 0.000000 -0.148438 0.326615 +v 0.000000 -0.226562 0.326615 +v 0.000000 -0.226562 0.326615 +v 0.000000 -0.289062 0.326615 +v 0.000000 -0.289062 0.326615 +v 0.000000 -0.046875 0.326615 +v 0.000000 -0.046875 0.326615 +v 0.000000 0.054688 0.326615 +v 0.000000 0.054688 0.326615 +v 0.000000 0.203125 0.326615 +v 0.000000 0.203125 0.326615 +v 0.000000 0.375000 0.326615 +v 0.000000 0.375000 0.326615 +v 0.000000 0.414062 0.326615 +v 0.000000 0.414062 0.326615 +v 0.000000 0.546875 0.326615 +v 0.000000 0.546875 0.326615 +v 0.000000 0.640625 0.326615 +v 0.000000 0.640625 0.326615 +v 0.000000 0.617188 0.326615 +v 0.000000 0.617188 0.326615 +v 0.000000 0.429688 0.326615 +v 0.000000 0.429688 0.326615 +v 0.000000 -0.101562 0.326615 +v 0.000000 -0.101562 0.326615 +v 0.000000 -0.445312 0.326615 +v 0.000000 -0.445312 0.326615 +v 0.000000 -0.703125 0.326615 +v 0.000000 -0.703125 0.326615 +v 0.000000 -0.820312 0.326615 +v 0.000000 -0.820312 0.326615 +v 0.000000 -0.914062 0.326615 +v 0.000000 -0.914062 0.326615 +v 0.000000 -0.929688 0.326615 +v 0.000000 -0.929688 0.326615 +v 0.000000 -0.945312 0.326615 +v 0.000000 0.046875 0.326615 +v 0.000000 0.210938 0.326615 +v 0.000000 0.476562 0.326615 +v 0.000000 0.476562 0.326615 +v 0.000000 0.140625 0.326615 +v 0.000000 0.140625 0.326615 +v 0.000000 0.210938 0.326615 +v 0.000000 0.210938 0.326615 +v 0.000000 -0.687500 0.326615 +v 0.000000 -0.687500 0.326615 +v 0.000000 -0.445312 0.326615 +v 0.000000 -0.445312 0.326615 +v 0.000000 -0.445312 0.326615 +v 0.000000 -0.328125 0.326615 +v 0.000000 -0.273438 0.326615 +v 0.000000 -0.273438 0.326615 +v 0.000000 -0.226562 0.326615 +v 0.000000 -0.226562 0.326615 +v 0.000000 -0.132812 0.326615 +v 0.000000 -0.132812 0.326615 +v 0.000000 -0.125000 0.326615 +v 0.000000 -0.125000 0.326615 +v 0.000000 -0.203125 0.326615 +v 0.000000 -0.148438 0.326615 +v 0.000000 -0.148438 0.326615 +v 0.000000 -0.156250 0.326615 +v 0.000000 -0.156250 0.326615 +v 0.000000 -0.226562 0.326615 +v 0.000000 -0.226562 0.326615 +v 0.000000 -0.250000 0.326615 +v 0.000000 -0.250000 0.326615 +v 0.000000 -0.289062 0.326615 +v 0.000000 -0.312500 0.326615 +v 0.000000 -0.312500 0.326615 +v 0.000000 -0.242188 0.326615 +v 0.000000 -0.242188 0.326615 +v 0.000000 -0.312500 0.326615 +v 0.000000 -0.312500 0.326615 +v 0.000000 -0.250000 0.326615 +v 0.000000 -0.250000 0.326615 +v 0.000000 -0.875000 0.326615 +v 0.000000 -0.867188 0.326615 +v 0.000000 -0.867188 0.326615 +v 0.000000 -0.820312 0.326615 +v 0.000000 -0.820312 0.326615 +v 0.000000 -0.742188 0.326615 +v 0.000000 -0.742188 0.326615 +v 0.000000 -0.781250 0.326615 +v 0.000000 -0.750000 0.326615 +v 0.000000 -0.750000 0.326615 +v 0.000000 -0.812500 0.326615 +v 0.000000 -0.812500 0.326615 +v 0.000000 -0.851562 0.326615 +v 0.000000 -0.851562 0.326615 +v 0.000000 -0.859375 0.326615 +v 0.000000 0.218750 0.326615 +v 0.000000 0.218750 0.326615 +v 0.000000 0.156250 0.326615 +v 0.000000 0.156250 0.326615 +v 0.000000 0.429688 0.326615 +v 0.000000 0.429688 0.326615 +v 0.000000 0.421875 0.326615 +v 0.000000 0.421875 0.326615 +v 0.000000 0.398438 0.326615 +v 0.000000 0.398438 0.326615 +v 0.000000 0.351562 0.326615 +v 0.000000 0.351562 0.326615 +v 0.000000 0.289062 0.326615 +v 0.000000 0.289062 0.326615 +v 0.000000 0.195312 0.326615 +v 0.000000 0.195312 0.326615 +v 0.000000 0.101562 0.326615 +v 0.000000 0.101562 0.326615 +v 0.000000 0.062500 0.326615 +v 0.000000 0.062500 0.326615 +v 0.000000 0.109375 0.326615 +v 0.000000 0.109375 0.326615 +v 0.000000 0.296875 0.326615 +v 0.000000 0.296875 0.326615 +v 0.000000 0.375000 0.326615 +v 0.000000 0.375000 0.326615 +v 0.000000 0.359375 0.326615 +v 0.000000 0.359375 0.326615 +v 0.000000 0.296875 0.326615 +v 0.000000 0.296875 0.326615 +v 0.000000 0.125000 0.326615 +v 0.000000 0.125000 0.326615 +v 0.000000 0.085938 0.326615 +v 0.000000 0.085938 0.326615 +v 0.000000 0.117188 0.326615 +v 0.000000 0.117188 0.326615 +v 0.000000 0.210938 0.326615 +v 0.000000 0.210938 0.326615 +v 0.000000 0.281250 0.326615 +v 0.000000 0.281250 0.326615 +v 0.000000 0.335938 0.326615 +v 0.000000 0.335938 0.326615 +v 0.000000 0.390625 0.326615 +v 0.000000 0.390625 0.326615 +v 0.000000 0.398438 0.326615 +v 0.000000 0.398438 0.326615 +v 0.000000 0.406250 0.326615 +v 0.000000 0.406250 0.326615 +v 0.000000 0.171875 0.326615 +v 0.000000 0.171875 0.326615 +v 0.000000 0.226562 0.326615 +v 0.000000 0.226562 0.326615 +v 0.000000 0.460938 0.326615 +v 0.000000 0.460938 0.326615 +v 0.000000 0.664062 0.326615 +v 0.000000 0.664062 0.326615 +v 0.000000 0.687500 0.326615 +v 0.000000 0.687500 0.326615 +v 0.000000 0.554688 0.326615 +v 0.000000 0.554688 0.326615 +v 0.000000 0.453125 0.326615 +v 0.000000 0.453125 0.326615 +v 0.000000 0.406250 0.326615 +v 0.000000 0.406250 0.326615 +v 0.000000 0.164062 0.326615 +v 0.000000 0.164062 0.326615 +v 0.000000 0.000000 0.326615 +v 0.000000 0.000000 0.326615 +v 0.000000 -0.093750 0.326615 +v 0.000000 -0.093750 0.326615 +v 0.000000 0.898438 0.326615 +v 0.000000 0.984375 0.326615 +v 0.000000 -0.195312 0.326615 +v 0.000000 -0.460938 0.326615 +v 0.000000 -0.976562 0.326615 +v 0.000000 -0.804688 0.326615 +v 0.000000 -0.570312 0.326615 +v 0.000000 -0.484375 0.326615 +v 0.000000 0.234375 0.326615 +v 0.000000 0.234375 0.326615 +v 0.000000 0.320312 0.326615 +v 0.000000 0.320312 0.326615 +v 0.000000 0.265625 0.326615 +v 0.000000 0.265625 0.326615 +v 0.000000 0.437500 0.326615 +v 0.000000 0.437500 0.326615 +v 0.000000 -0.046875 0.326615 +v 0.000000 -0.046875 0.326615 +v 0.000000 -0.125000 0.326615 +v 0.000000 -0.125000 0.326615 +v 0.000000 -0.007812 0.326615 +v 0.000000 -0.007812 0.326615 +v 0.000000 0.054688 0.326615 +v 0.000000 0.054688 0.326615 +v 0.000000 -0.351562 0.326615 +v 0.000000 -0.351562 0.326615 +v 0.000000 -0.414062 0.326615 +v 0.000000 -0.414062 0.326615 +v 0.000000 -0.710938 0.326615 +v 0.000000 -0.710938 0.326615 +v 0.000000 -0.500000 0.326615 +v 0.000000 -0.500000 0.326615 +v 0.000000 -0.914062 0.326615 +v 0.000000 -0.914062 0.326615 +v 0.000000 -0.757812 0.326615 +v 0.000000 -0.757812 0.326615 +v 0.000000 -0.539062 0.326615 +v 0.000000 -0.539062 0.326615 +v 0.000000 -0.945312 0.326615 +v 0.000000 -0.945312 0.326615 +v 0.000000 -0.281250 0.326615 +v 0.000000 -0.281250 0.326615 +v 0.000000 -0.226562 0.326615 +v 0.000000 -0.226562 0.326615 +v 0.000000 -0.171875 0.326615 +v 0.000000 -0.171875 0.326615 +v 0.000000 -0.390625 0.326615 +v 0.000000 -0.390625 0.326615 +v 0.000000 -0.312500 0.326615 +v 0.000000 -0.312500 0.326615 +v 0.000000 -0.148438 0.326615 +v 0.000000 -0.148438 0.326615 +v 0.000000 0.867188 0.326615 +v 0.000000 0.867188 0.326615 +v 0.000000 0.929688 0.326615 +v 0.000000 0.929688 0.326615 +v 0.000000 0.851562 0.326615 +v 0.000000 0.851562 0.326615 +v 0.000000 0.523438 0.326615 +v 0.000000 0.523438 0.326615 +v 0.000000 0.406250 0.326615 +v 0.000000 0.406250 0.326615 +v 0.000000 0.453125 0.326615 +v 0.000000 0.453125 0.326615 +v 0.000000 0.703125 0.326615 +v 0.000000 0.703125 0.326615 +v 0.000000 0.562500 0.326615 +v 0.000000 0.562500 0.326615 +v 0.000000 0.617188 0.326615 +v 0.000000 0.617188 0.326615 +v 0.000000 0.750000 0.326615 +v 0.000000 0.750000 0.326615 +v 0.000000 0.679688 0.326615 +v 0.000000 0.679688 0.326615 +v 0.000000 0.539062 0.326615 +v 0.000000 0.539062 0.326615 +v 0.000000 0.328125 0.326615 +v 0.000000 0.328125 0.326615 +v 0.000000 0.023438 0.326615 +v 0.000000 0.023438 0.326615 +v 0.000000 0.328125 0.326615 +v 0.000000 0.328125 0.326615 +v 0.000000 -0.171875 0.326615 +v 0.000000 -0.171875 0.326615 +v 0.000000 -0.195312 0.326615 +v 0.000000 -0.195312 0.326615 +v 0.000000 0.406250 0.326615 +v 0.000000 0.406250 0.326615 +v 0.000000 -0.140625 0.326615 +v 0.000000 -0.140625 0.326615 +v 0.000000 -0.101562 0.326615 +v 0.000000 -0.101562 0.326615 +v 0.000000 0.054688 0.326615 +v 0.000000 0.054688 0.326615 +v 0.000000 0.320312 0.326615 +v 0.000000 0.320312 0.326615 +v 0.000000 0.507812 0.326615 +v 0.000000 0.507812 0.326615 +v 0.000000 0.476562 0.326615 +v 0.000000 0.476562 0.326615 +v 0.000000 0.414062 0.326615 +v 0.000000 0.414062 0.326615 +v 0.000000 0.437500 0.326615 +v 0.000000 0.437500 0.326615 +v 0.000000 0.289062 0.326615 +v 0.000000 0.289062 0.326615 +v 0.000000 0.078125 0.326615 +v 0.000000 0.078125 0.326615 +v 0.000000 -0.039062 0.326615 +v 0.000000 -0.039062 0.326615 +v 0.000000 -0.070312 0.326615 +v 0.000000 -0.070312 0.326615 +v 0.000000 0.359375 0.326615 +v 0.000000 0.359375 0.326615 +v 0.000000 0.304688 0.326615 +v 0.000000 0.304688 0.326615 +v 0.000000 -0.023438 0.326615 +v 0.000000 -0.023438 0.326615 +v 0.000000 0.000000 0.326615 +v 0.000000 0.000000 0.326615 +v 0.000000 0.093750 0.326615 +v 0.000000 0.093750 0.326615 +v 0.000000 0.250000 0.326615 +v 0.000000 0.250000 0.326615 +v 0.000000 0.359375 0.326615 +v 0.000000 0.359375 0.326615 +v 0.000000 0.343750 0.326615 +v 0.000000 0.343750 0.326615 +v 0.000000 0.289062 0.326615 +v 0.000000 0.289062 0.326615 +v 0.000000 0.171875 0.326615 +v 0.000000 0.171875 0.326615 +v 0.000000 0.093750 0.326615 +v 0.000000 0.093750 0.326615 +v 0.000000 0.085938 0.326615 +v 0.000000 0.085938 0.326615 +v 0.000000 0.015625 0.326615 +v 0.000000 0.015625 0.326615 +v 0.000000 -0.015625 0.326615 +v 0.000000 -0.015625 0.326615 +v 0.000000 0.000000 0.326615 +v 0.000000 0.000000 0.326615 +v 0.000000 -0.023438 0.326615 +v 0.000000 -0.023438 0.326615 +v 0.000000 0.039062 0.326615 +v 0.000000 0.039062 0.326615 +v 0.000000 0.203125 0.326615 +v 0.000000 0.203125 0.326615 +v 0.000000 0.242188 0.326615 +v 0.000000 0.242188 0.326615 +v 0.000000 0.234375 0.326615 +v 0.000000 0.234375 0.326615 +v 0.000000 -0.015625 0.326615 +v 0.000000 -0.015625 0.326615 +v 0.000000 0.015625 0.326615 +v 0.000000 0.015625 0.326615 +v 0.000000 0.078125 0.326615 +v 0.000000 0.078125 0.326615 +v 0.000000 0.093750 0.326615 +v 0.000000 0.093750 0.326615 +v 0.000000 0.171875 0.326615 +v 0.000000 0.171875 0.326615 +v 0.000000 0.328125 0.326615 +v 0.000000 0.328125 0.326615 +v 0.000000 0.343750 0.326615 +v 0.000000 0.343750 0.326615 +v 0.000000 0.242188 0.326615 +v 0.000000 0.242188 0.326615 +v 0.000000 0.085938 0.326615 +v 0.000000 0.085938 0.326615 +v 0.000000 0.000000 0.326615 +v 0.000000 0.000000 0.326615 +v 0.000000 -0.015625 0.326615 +v 0.000000 -0.015625 0.326615 +v 0.000000 0.289062 0.326615 +v 0.000000 0.289062 0.326615 +v 0.000000 0.109375 0.326615 +v 0.000000 0.109375 0.326615 +v 0.000000 0.062500 0.326615 +v 0.000000 0.062500 0.326615 +v 0.000000 0.125000 0.326615 +v 0.000000 0.125000 0.326615 +v 0.000000 0.171875 0.326615 +v 0.000000 0.171875 0.326615 +v 0.000000 0.234375 0.326615 +v 0.000000 0.234375 0.326615 +v 0.000000 0.187500 0.326615 +v 0.000000 0.187500 0.326615 +v 0.000000 0.210938 0.326615 +v 0.000000 0.210938 0.326615 +v 0.000000 0.273438 0.326615 +v 0.000000 0.273438 0.326615 +v 0.000000 0.437500 0.326615 +v 0.000000 0.437500 0.326615 +v 0.000000 0.468750 0.326615 +v 0.000000 0.468750 0.326615 +v 0.000000 0.296875 0.326615 +v 0.000000 0.296875 0.326615 +v 0.000000 0.054688 0.326615 +v 0.000000 0.054688 0.326615 +v 0.000000 -0.085938 0.326615 +v 0.000000 -0.085938 0.326615 +v 0.000000 -0.125000 0.326615 +v 0.000000 -0.125000 0.326615 +v 0.000000 0.382812 0.326615 +v 0.000000 0.382812 0.326615 +vn -0.0000 1.0000 -0.0000 +vn -1.0000 -0.0000 -0.0000 +vn 1.0000 -0.0000 -0.0000 +vt 0.500000 0.590063 +vt 0.500000 0.560115 +vt 0.500000 0.559404 +vt 0.500000 0.850547 +vt 0.500000 0.821999 +vt 0.500000 0.853232 +vt 0.500000 0.521562 +vt 0.500000 0.524546 +vt 0.500000 0.888748 +vt 0.500000 0.569535 +vt 0.500000 0.838402 +vt 0.500000 0.589649 +vt 0.500000 0.590771 +vt 0.500000 0.818537 +vt 0.500000 0.821510 +vt 0.500000 0.604754 +vt 0.500000 0.633354 +vt 0.500000 0.775964 +vt 0.500000 0.805700 +vt 0.500000 0.645443 +vt 0.500000 0.762238 +vt 0.500000 0.702491 +vt 0.500000 0.707525 +vt 0.500000 0.625459 +vt 0.500000 0.668527 +vt 0.500000 0.742025 +vt 0.500000 0.785002 +vt 0.500000 0.642291 +vt 0.500000 0.666964 +vt 0.500000 0.745592 +vt 0.500000 0.768782 +vt 0.500000 0.699697 +vt 0.500000 0.713713 +vt 0.500000 0.645333 +vt 0.500000 0.770220 +vt 0.500000 0.641909 +vt 0.500000 0.636832 +vt 0.500000 0.777093 +vt 0.500000 0.770183 +vt 0.500000 0.627902 +vt 0.500000 0.593037 +vt 0.500000 0.820926 +vt 0.500000 0.784860 +vt 0.500000 0.573812 +vt 0.500000 0.841671 +vt 0.500000 0.605742 +vt 0.500000 0.807013 +vt 0.500000 0.607909 +vt 0.500000 0.593275 +vt 0.500000 0.804677 +vt 0.500000 0.818729 +vt 0.500000 0.626257 +vt 0.500000 0.786233 +vt 0.500000 0.636527 +vt 0.500000 0.775442 +vt 0.500000 0.635245 +vt 0.500000 0.775972 +vt 0.500000 0.623942 +vt 0.500000 0.786774 +vt 0.500000 0.608186 +vt 0.500000 0.802505 +vt 0.500000 0.593961 +vt 0.500000 0.817249 +vt 0.500000 0.616512 +vt 0.500000 0.795063 +vt 0.500000 0.053805 +vt 0.500000 0.059681 +vt 0.500000 0.050294 +vt 0.500000 0.053770 +vt 0.500000 0.058338 +vt 0.500000 0.062072 +vt 0.500000 0.062043 +vt 0.500000 0.058273 +vt 0.500000 0.061900 +vt 0.500000 0.064089 +vt 0.500000 0.064047 +vt 0.500000 0.061829 +vt 0.500000 0.076586 +vt 0.500000 0.072669 +vt 0.500000 0.072625 +vt 0.500000 0.076511 +vt 0.500000 0.108495 +vt 0.500000 0.084893 +vt 0.500000 0.084858 +vt 0.500000 0.108481 +vt 0.500000 0.165134 +vt 0.500000 0.227818 +vt 0.500000 0.209599 +vt 0.500000 0.229490 +vt 0.500000 0.165644 +vt 0.500000 0.210053 +vt 0.500000 0.200502 +vt 0.500000 0.253225 +vt 0.500000 0.256357 +vt 0.500000 0.201890 +vt 0.500000 0.233241 +vt 0.500000 0.279995 +vt 0.500000 0.284606 +vt 0.500000 0.235899 +vt 0.500000 0.265392 +vt 0.500000 0.311539 +vt 0.500000 0.317440 +vt 0.500000 0.270303 +vt 0.500000 0.310054 +vt 0.500000 0.323937 +vt 0.500000 0.329722 +vt 0.500000 0.316853 +vt 0.500000 0.332673 +vt 0.500000 0.357330 +vt 0.500000 0.362131 +vt 0.500000 0.339667 +vt 0.500000 0.372521 +vt 0.500000 0.375151 +vt 0.500000 0.379267 +vt 0.500000 0.378686 +vt 0.500000 0.397804 +vt 0.500000 0.395792 +vt 0.500000 0.401540 +vt 0.500000 0.381222 +vt 0.500000 0.390512 +vt 0.500000 0.377857 +vt 0.500000 0.391862 +vt 0.500000 0.358497 +vt 0.500000 0.386009 +vt 0.500000 0.357011 +vt 0.500000 0.343868 +vt 0.500000 0.344815 +vt 0.500000 0.340156 +vt 0.500000 0.347815 +vt 0.500000 0.342005 +vt 0.500000 0.345582 +vt 0.500000 0.332311 +vt 0.500000 0.312804 +vt 0.500000 0.317685 +vt 0.500000 0.336480 +vt 0.500000 0.297958 +vt 0.500000 0.302644 +vt 0.500000 0.277872 +vt 0.500000 0.281778 +vt 0.500000 0.253047 +vt 0.500000 0.255633 +vt 0.500000 0.242662 +vt 0.500000 0.244473 +vt 0.500000 0.258564 +vt 0.500000 0.259709 +vt 0.500000 0.248864 +vt 0.500000 0.316594 +vt 0.500000 0.342230 +vt 0.500000 0.317843 +vt 0.500000 0.294764 +vt 0.500000 0.291214 +vt 0.500000 0.292249 +vt 0.500000 0.068967 +vt 0.500000 0.068956 +vt 0.500000 0.073829 +vt 0.500000 0.073811 +vt 0.500000 0.087431 +vt 0.500000 0.087416 +vt 0.500000 0.121749 +vt 0.500000 0.090920 +vt 0.500000 0.090908 +vt 0.500000 0.121781 +vt 0.500000 0.158382 +vt 0.500000 0.128358 +vt 0.500000 0.127713 +vt 0.500000 0.158434 +vt 0.500000 0.127728 +vt 0.500000 0.093952 +vt 0.500000 0.085180 +vt 0.500000 0.173560 +vt 0.500000 0.166808 +vt 0.500000 0.166857 +vt 0.500000 0.173693 +vt 0.500000 0.193366 +vt 0.500000 0.175966 +vt 0.500000 0.176033 +vt 0.500000 0.193428 +vt 0.500000 0.200843 +vt 0.500000 0.187577 +vt 0.500000 0.187571 +vt 0.500000 0.190607 +vt 0.500000 0.191785 +vt 0.500000 0.191626 +vt 0.500000 0.151749 +vt 0.500000 0.159028 +vt 0.500000 0.171631 +vt 0.500000 0.165599 +vt 0.500000 0.171667 +vt 0.500000 0.185382 +vt 0.500000 0.186316 +vt 0.500000 0.186260 +vt 0.500000 0.184215 +vt 0.500000 0.184206 +vt 0.500000 0.176791 +vt 0.500000 0.179457 +vt 0.500000 0.176739 +vt 0.500000 0.167779 +vt 0.500000 0.167996 +vt 0.500000 0.149319 +vt 0.500000 0.149447 +vt 0.500000 0.133426 +vt 0.500000 0.133592 +vt 0.500000 0.147885 +vt 0.500000 0.148194 +vt 0.500000 0.083865 +vt 0.500000 0.084957 +vt 0.500000 0.084945 +vt 0.500000 0.075429 +vt 0.500000 0.075415 +vt 0.500000 0.070508 +vt 0.500000 0.070501 +vt 0.500000 0.067899 +vt 0.500000 0.069468 +vt 0.500000 0.074970 +vt 0.500000 0.074259 +vt 0.500000 0.074966 +vt 0.500000 0.076691 +vt 0.500000 0.076684 +vt 0.500000 0.079886 +vt 0.500000 0.079879 +vt 0.500000 0.079331 +vt 0.500000 0.277295 +vt 0.500000 0.292904 +vt 0.500000 0.278617 +vt 0.500000 0.294282 +vt 0.500000 0.311386 +vt 0.500000 0.313081 +vt 0.500000 0.327708 +vt 0.500000 0.329961 +vt 0.500000 0.272007 +vt 0.500000 0.266620 +vt 0.500000 0.268049 +vt 0.500000 0.273078 +vt 0.500000 0.255725 +vt 0.500000 0.257728 +vt 0.500000 0.262853 +vt 0.500000 0.265508 +vt 0.500000 0.279971 +vt 0.500000 0.283634 +vt 0.500000 0.297636 +vt 0.500000 0.301864 +vt 0.500000 0.310186 +vt 0.500000 0.314615 +vt 0.500000 0.323864 +vt 0.500000 0.327673 +vt 0.500000 0.331972 +vt 0.500000 0.335361 +vt 0.500000 0.333624 +vt 0.500000 0.336537 +vt 0.500000 0.321516 +vt 0.500000 0.328453 +vt 0.500000 0.323919 +vt 0.500000 0.331331 +vt 0.500000 0.327083 +vt 0.500000 0.330358 +vt 0.500000 0.320513 +vt 0.500000 0.324175 +vt 0.500000 0.306421 +vt 0.500000 0.310510 +vt 0.500000 0.296225 +vt 0.500000 0.300183 +vt 0.500000 0.283486 +vt 0.500000 0.287071 +vt 0.500000 0.267263 +vt 0.500000 0.269959 +vt 0.500000 0.261560 +vt 0.500000 0.263693 +vt 0.500000 0.270991 +vt 0.500000 0.272583 +vt 0.500000 0.281900 +vt 0.500000 0.283441 +vt 0.500000 0.309340 +vt 0.500000 0.311233 +vt 0.500000 0.293776 +vt 0.500000 0.295432 +vt 0.500000 0.433063 +vt 0.500000 0.433628 +vt 0.500000 0.434538 +vt 0.500000 0.431516 +vt 0.500000 0.435740 +vt 0.500000 0.419316 +vt 0.500000 0.425416 +vt 0.500000 0.388274 +vt 0.500000 0.396229 +vt 0.500000 0.400552 +vt 0.500000 0.341754 +vt 0.500000 0.350588 +vt 0.500000 0.312112 +vt 0.500000 0.320593 +vt 0.500000 0.256393 +vt 0.500000 0.261087 +vt 0.500000 0.216906 +vt 0.500000 0.219179 +vt 0.500000 0.190671 +vt 0.500000 0.191872 +vt 0.500000 0.015608 +vt 0.500000 0.076084 +vt 0.500000 0.048089 +vt 0.500000 0.075296 +vt 0.500000 0.015131 +vt 0.500000 0.047631 +vt 0.500000 0.000144 +vt 0.500000 0.032801 +vt 0.500000 0.032656 +vt 0.500000 0.024886 +vt 0.500000 0.041724 +vt 0.500000 0.041669 +vt 0.500000 0.053871 +vt 0.500000 0.053785 +vt 0.500000 0.057998 +vt 0.500000 0.057845 +vt 0.500000 0.078268 +vt 0.500000 0.077985 +vt 0.500000 0.111357 +vt 0.500000 0.111244 +vt 0.500000 0.146796 +vt 0.500000 0.147158 +vt 0.500000 0.130456 +vt 0.500000 0.130594 +vt 0.500000 0.159841 +vt 0.500000 0.160361 +vt 0.500000 0.079569 +vt 0.500000 0.099732 +vt 0.500000 0.036916 +vt 0.500000 0.092127 +vt 0.500000 0.060719 +vt 0.500000 0.021467 +vt 0.500000 0.080826 +vt 0.500000 0.010786 +vt 0.500000 0.076510 +vt 0.500000 0.003484 +vt 0.500000 0.077204 +vt 0.500000 0.022201 +vt 0.500000 0.075955 +vt 0.500000 0.020991 +vt 0.500000 0.022378 +vt 0.500000 0.021586 +vt 0.500000 0.193244 +vt 0.500000 0.233323 +vt 0.500000 0.193871 +vt 0.500000 0.236977 +vt 0.500000 0.167705 +vt 0.500000 0.121777 +vt 0.500000 0.112482 +vt 0.500000 0.155367 +vt 0.500000 0.402429 +vt 0.500000 0.301884 +vt 0.500000 0.344752 +vt 0.500000 0.315519 +vt 0.500000 0.432652 +vt 0.500000 0.367038 +vt 0.500000 0.254640 +vt 0.500000 0.259113 +vt 0.500000 0.266968 +vt 0.500000 0.183261 +vt 0.500000 0.179083 +vt 0.500000 0.334683 +vt 0.500000 0.300809 +vt 0.500000 0.313727 +vt 0.500000 0.310142 +vt 0.500000 0.346496 +vt 0.500000 0.325552 +vt 0.500000 0.276388 +vt 0.500000 0.293397 +vt 0.500000 0.285164 +vt 0.500000 0.304983 +vt 0.500000 0.256352 +vt 0.500000 0.265922 +vt 0.500000 0.263312 +vt 0.500000 0.274284 +vt 0.500000 0.233769 +vt 0.500000 0.237587 +vt 0.500000 0.231720 +vt 0.500000 0.195160 +vt 0.500000 0.228168 +vt 0.500000 0.196179 +vt 0.500000 0.184705 +vt 0.500000 0.182749 +vt 0.500000 0.259804 +vt 0.500000 0.338556 +vt 0.500000 0.356821 +vt 0.500000 0.379538 +vt 0.500000 0.364062 +vt 0.500000 0.398737 +vt 0.500000 0.382592 +vt 0.500000 0.449967 +vt 0.500000 0.484099 +vt 0.500000 0.445381 +vt 0.500000 0.418603 +vt 0.500000 0.442912 +vt 0.500000 0.477186 +vt 0.500000 0.468071 +vt 0.500000 0.503605 +vt 0.500000 0.219562 +vt 0.500000 0.233887 +vt 0.500000 0.222464 +vt 0.500000 0.139727 +vt 0.500000 0.139409 +vt 0.500000 0.114850 +vt 0.500000 0.152330 +vt 0.500000 0.151002 +vt 0.500000 0.137775 +vt 0.500000 0.132294 +vt 0.500000 0.117591 +vt 0.500000 0.156361 +vt 0.500000 0.155241 +vt 0.500000 0.904851 +vt 0.500000 0.870229 +vt 0.500000 0.881714 +vt 0.500000 0.868209 +vt 0.500000 0.901159 +vt 0.500000 0.878321 +vt 0.500000 0.860484 +vt 0.500000 0.879946 +vt 0.500000 0.854693 +vt 0.500000 0.873349 +vt 0.500000 0.793977 +vt 0.500000 0.791615 +vt 0.500000 0.787474 +vt 0.500000 0.784093 +vt 0.500000 0.746412 +vt 0.500000 0.739211 +vt 0.500000 0.740879 +vt 0.500000 0.733241 +vt 0.500000 0.711729 +vt 0.500000 0.697693 +vt 0.500000 0.707497 +vt 0.500000 0.693249 +vt 0.500000 0.680683 +vt 0.500000 0.658882 +vt 0.500000 0.677959 +vt 0.500000 0.656224 +vt 0.500000 0.700023 +vt 0.500000 0.696976 +vt 0.500000 0.730944 +vt 0.500000 0.726592 +vt 0.500000 0.755753 +vt 0.500000 0.750414 +vt 0.500000 0.787367 +vt 0.500000 0.781375 +vt 0.500000 0.826352 +vt 0.500000 0.820889 +vt 0.500000 0.840040 +vt 0.500000 0.844356 +vt 0.500000 0.837358 +vt 0.500000 0.840502 +vt 0.500000 0.176969 +vt 0.500000 0.187449 +vt 0.500000 0.175620 +vt 0.500000 0.187075 +vt 0.500000 0.611891 +vt 0.500000 0.686125 +vt 0.500000 0.610196 +vt 0.500000 0.684445 +vt 0.500000 0.237388 +vt 0.500000 0.862097 +vt 0.500000 0.894943 +vt 0.500000 0.861308 +vt 0.500000 0.893225 +vt 0.500000 0.715731 +vt 0.500000 0.729661 +vt 0.500000 0.718280 +vt 0.500000 0.727177 +vt 0.500000 0.747662 +vt 0.500000 0.742828 +vt 0.500000 0.745816 +vt 0.500000 0.740536 +vt 0.500000 0.784946 +vt 0.500000 0.710299 +vt 0.500000 0.708969 +vt 0.500000 0.783073 +vt 0.500000 0.841460 +vt 0.500000 0.817535 +vt 0.500000 0.840297 +vt 0.500000 0.815460 +vt 0.500000 0.209762 +vt 0.500000 0.214827 +vt 0.500000 0.203086 +vt 0.500000 0.206161 +vt 0.500000 0.183086 +vt 0.500000 0.184609 +vt 0.500000 0.804621 +vt 0.500000 0.824700 +vt 0.500000 0.802031 +vt 0.500000 0.821525 +vt 0.500000 0.779569 +vt 0.500000 0.777208 +vt 0.500000 0.754191 +vt 0.500000 0.752045 +vt 0.500000 0.749777 +vt 0.500000 0.747250 +vt 0.500000 0.731997 +vt 0.500000 0.729222 +vt 0.500000 0.724383 +vt 0.500000 0.721697 +vt 0.500000 0.713731 +vt 0.500000 0.710657 +vt 0.500000 0.828811 +vt 0.500000 0.824574 +vt 0.500000 0.811814 +vt 0.500000 0.806417 +vt 0.500000 0.787682 +vt 0.500000 0.782156 +vt 0.500000 0.764539 +vt 0.500000 0.759319 +vt 0.500000 0.743135 +vt 0.500000 0.738732 +vt 0.500000 0.748408 +vt 0.500000 0.761665 +vt 0.500000 0.745020 +vt 0.500000 0.758742 +vt 0.500000 0.770464 +vt 0.500000 0.783904 +vt 0.500000 0.766661 +vt 0.500000 0.780511 +vt 0.500000 0.787562 +vt 0.500000 0.802470 +vt 0.500000 0.783410 +vt 0.500000 0.798626 +vt 0.500000 0.791602 +vt 0.500000 0.807339 +vt 0.500000 0.787045 +vt 0.500000 0.802891 +vt 0.500000 0.628776 +vt 0.500000 0.683538 +vt 0.500000 0.625067 +vt 0.500000 0.678120 +vt 0.500000 0.726933 +vt 0.500000 0.720426 +vt 0.500000 0.759965 +vt 0.500000 0.752377 +vt 0.500000 0.759884 +vt 0.500000 0.741167 +vt 0.500000 0.748824 +vt 0.500000 0.732052 +vt 0.500000 0.652100 +vt 0.500000 0.670436 +vt 0.500000 0.639749 +vt 0.500000 0.662038 +vt 0.500000 0.572428 +vt 0.500000 0.592656 +vt 0.500000 0.564403 +vt 0.500000 0.589862 +vt 0.500000 0.206879 +vt 0.500000 0.206959 +vt 0.500000 0.562595 +vt 0.500000 0.565675 +vt 0.500000 0.552315 +vt 0.500000 0.550140 +vt 0.500000 0.444261 +vt 0.500000 0.473316 +vt 0.500000 0.795423 +vt 0.500000 0.794472 +vt 0.500000 0.522659 +s 0 +f 47/1/1 3/2/1 45/3/1 +f 4/4/1 48/5/1 46/6/1 +f 45/3/1 5/7/1 43/8/1 +f 6/9/1 46/6/1 44/9/1 +f 3/2/1 7/10/1 5/7/1 +f 8/11/1 4/4/1 6/9/1 +f 1/12/1 9/13/1 3/2/1 +f 10/14/1 2/15/1 4/4/1 +f 11/16/1 15/17/1 9/13/1 +f 16/18/1 12/19/1 10/14/1 +f 9/13/1 17/20/1 7/10/1 +f 18/21/1 10/14/1 8/11/1 +f 15/17/1 19/22/1 17/20/1 +f 20/23/1 16/18/1 18/21/1 +f 13/24/1 21/25/1 15/17/1 +f 22/26/1 14/27/1 16/18/1 +f 23/28/1 27/29/1 21/25/1 +f 28/30/1 24/31/1 22/26/1 +f 21/25/1 29/32/1 19/22/1 +f 30/33/1 22/26/1 20/23/1 +f 27/29/1 31/34/1 29/32/1 +f 32/35/1 28/30/1 30/33/1 +f 25/36/1 33/37/1 27/29/1 +f 34/38/1 26/39/1 28/30/1 +f 35/40/1 39/41/1 33/37/1 +f 40/42/1 36/43/1 34/38/1 +f 33/37/1 41/44/1 31/34/1 +f 42/45/1 34/38/1 32/35/1 +f 39/41/1 43/8/1 41/44/1 +f 44/9/1 40/42/1 42/45/1 +f 37/46/1 45/3/1 39/41/1 +f 46/6/1 38/47/1 40/42/1 +f 47/1/1 51/48/1 49/49/1 +f 52/50/1 48/5/1 50/51/1 +f 37/46/1 53/52/1 51/48/1 +f 54/53/1 38/47/1 52/50/1 +f 35/40/1 55/54/1 53/52/1 +f 56/55/1 36/43/1 54/53/1 +f 25/36/1 57/56/1 55/54/1 +f 58/57/1 26/39/1 56/55/1 +f 23/28/1 59/58/1 57/56/1 +f 60/59/1 24/31/1 58/57/1 +f 13/24/1 63/60/1 59/58/1 +f 64/61/1 14/27/1 60/59/1 +f 11/16/1 65/62/1 63/60/1 +f 66/63/1 12/19/1 64/61/1 +f 1/12/1 49/49/1 65/62/1 +f 50/51/1 2/15/1 66/63/1 +f 61/64/2 65/62/2 49/49/2 +f 50/51/3 66/63/3 62/65/3 +f 63/60/2 65/62/2 61/64/2 +f 62/65/3 66/63/3 64/61/3 +f 61/64/3 59/58/3 63/60/3 +f 64/61/2 60/59/2 62/65/2 +f 61/64/3 57/56/3 59/58/3 +f 60/59/2 58/57/2 62/65/2 +f 61/64/3 55/54/3 57/56/3 +f 58/57/2 56/55/2 62/65/2 +f 61/64/3 53/52/3 55/54/3 +f 56/55/2 54/53/2 62/65/2 +f 61/64/2 51/48/2 53/52/2 +f 54/53/3 52/50/3 62/65/3 +f 61/64/2 49/49/2 51/48/2 +f 52/50/3 50/51/3 62/65/3 +f 89/66/1 176/67/1 91/68/1 +f 176/67/1 90/69/1 91/68/1 +f 87/70/1 174/71/1 89/66/1 +f 175/72/1 88/73/1 90/69/1 +f 85/74/1 172/75/1 87/70/1 +f 173/76/1 86/77/1 88/73/1 +f 83/78/1 170/79/1 85/74/1 +f 171/80/1 84/81/1 86/77/1 +f 81/82/1 168/83/1 83/78/1 +f 169/84/1 82/85/1 84/81/1 +f 79/86/1 146/87/1 164/88/1 +f 147/89/1 80/90/1 165/91/1 +f 92/92/1 148/93/1 146/87/1 +f 149/94/1 93/95/1 147/89/1 +f 94/96/1 150/97/1 148/93/1 +f 151/98/1 95/99/1 149/94/1 +f 96/100/1 152/101/1 150/97/1 +f 153/102/1 97/103/1 151/98/1 +f 98/104/1 154/105/1 152/101/1 +f 155/106/1 99/107/1 153/102/1 +f 100/108/1 156/109/1 154/105/1 +f 157/110/1 101/111/1 155/106/1 +f 102/112/2 158/113/2 156/109/2 +f 159/114/3 103/115/3 157/110/3 +f 106/116/3 158/113/3 104/117/3 +f 107/118/2 159/114/2 161/119/2 +f 108/120/3 160/121/3 106/116/3 +f 109/122/2 161/119/2 163/123/2 +f 67/124/3 162/125/3 108/120/3 +f 67/124/2 163/123/2 68/126/2 +f 128/127/2 162/125/2 110/128/2 +f 129/129/3 163/123/3 161/119/3 +f 179/130/2 160/121/2 128/127/2 +f 180/131/3 161/119/3 159/114/3 +f 156/109/1 179/130/1 126/132/1 +f 157/110/3 180/131/3 159/114/3 +f 124/133/1 156/109/1 126/132/1 +f 157/110/1 125/134/1 127/135/1 +f 122/136/1 154/105/1 124/133/1 +f 155/106/1 123/137/1 125/134/1 +f 120/138/1 152/101/1 122/136/1 +f 153/102/1 121/139/1 123/137/1 +f 118/140/1 150/97/1 120/138/1 +f 151/98/1 119/141/1 121/139/1 +f 116/142/1 148/93/1 118/140/1 +f 149/94/1 117/143/1 119/141/1 +f 114/144/1 146/87/1 116/142/1 +f 147/89/1 115/145/1 117/143/1 +f 114/144/1 177/146/1 164/88/1 +f 177/146/1 115/145/1 165/91/1 +f 110/128/1 68/126/1 112/147/1 +f 68/126/1 111/148/1 113/149/1 +f 112/147/1 178/150/1 183/151/1 +f 178/150/1 113/149/1 184/152/1 +f 177/146/1 183/151/1 178/150/1 +f 184/152/1 177/146/1 178/150/1 +f 135/153/1 176/67/1 174/71/1 +f 176/67/1 136/154/1 175/72/1 +f 133/155/1 174/71/1 172/75/1 +f 175/72/1 134/156/1 173/76/1 +f 131/157/1 172/75/1 170/79/1 +f 173/76/1 132/158/1 171/80/1 +f 166/159/1 185/160/1 168/83/1 +f 186/161/1 167/162/1 169/84/1 +f 131/157/1 168/83/1 185/160/1 +f 169/84/1 132/158/1 186/161/1 +f 144/163/1 189/164/1 187/165/1 +f 189/164/1 145/166/1 188/167/1 +f 185/160/1 189/164/1 69/168/1 +f 189/164/1 186/161/1 69/168/1 +f 130/169/1 185/160/1 69/168/1 +f 186/161/1 130/169/1 69/168/1 +f 142/170/1 191/171/1 144/163/1 +f 192/172/1 143/173/1 145/166/1 +f 140/174/1 193/175/1 142/170/1 +f 194/176/1 141/177/1 143/173/1 +f 139/178/1 195/179/1 140/174/1 +f 196/180/1 139/178/1 141/177/1 +f 138/181/1 197/182/1 139/178/1 +f 198/183/1 138/181/1 139/178/1 +f 190/184/1 191/171/1 70/185/1 +f 192/172/1 190/184/1 70/185/1 +f 70/185/1 206/186/1 208/187/1 +f 207/188/1 70/185/1 208/187/1 +f 71/189/1 200/190/1 197/182/1 +f 201/191/1 71/189/1 198/183/1 +f 197/182/1 202/192/1 195/179/1 +f 203/193/1 198/183/1 196/180/1 +f 202/192/1 193/175/1 195/179/1 +f 203/193/3 194/176/3 205/194/3 +f 193/175/1 206/186/1 191/171/1 +f 207/188/1 194/176/1 192/172/1 +f 199/195/2 202/192/2 200/190/2 +f 203/193/3 199/195/3 201/191/3 +f 199/195/3 206/186/3 204/196/3 +f 207/188/2 199/195/2 205/194/2 +f 139/178/1 164/88/1 177/146/1 +f 165/91/1 139/178/1 177/146/1 +f 140/174/1 211/197/1 164/88/1 +f 212/198/1 141/177/1 165/91/1 +f 142/170/1 213/199/1 211/197/1 +f 214/200/1 143/173/1 212/198/1 +f 144/163/1 166/159/1 213/199/1 +f 167/162/1 145/166/1 214/200/1 +f 81/82/1 213/199/1 166/159/1 +f 214/200/1 82/85/1 167/162/1 +f 209/201/1 211/197/1 213/199/1 +f 212/198/1 210/202/1 214/200/1 +f 79/86/1 211/197/1 215/203/1 +f 212/198/1 80/90/1 216/204/1 +f 131/157/1 72/205/1 222/206/1 +f 72/205/1 132/158/1 223/207/1 +f 133/155/1 222/206/1 220/208/1 +f 223/207/1 134/156/1 221/209/1 +f 135/153/1 220/208/1 218/210/1 +f 221/209/1 136/154/1 219/211/1 +f 137/212/1 218/210/1 217/213/1 +f 219/211/1 137/212/1 217/213/1 +f 217/213/1 229/214/1 231/215/1 +f 230/216/1 217/213/1 231/215/1 +f 218/210/1 227/217/1 229/214/1 +f 228/218/1 219/211/1 230/216/1 +f 220/208/1 225/219/1 227/217/1 +f 226/220/1 221/209/1 228/218/1 +f 222/206/1 224/221/1 225/219/1 +f 224/221/1 223/207/1 226/220/1 +f 224/221/1 229/214/1 225/219/1 +f 230/216/1 224/221/1 226/220/1 +f 225/219/1 229/214/1 227/217/1 +f 228/218/1 230/216/1 226/220/1 +f 183/151/1 234/222/1 232/223/1 +f 235/224/1 184/152/1 233/225/1 +f 112/147/1 232/223/1 254/226/1 +f 233/225/1 113/149/1 255/227/1 +f 110/128/1 254/226/1 256/228/1 +f 255/227/1 111/148/1 257/229/1 +f 181/230/1 252/231/1 234/222/1 +f 253/232/1 182/233/1 235/224/1 +f 114/144/1 250/234/1 252/231/1 +f 251/235/1 115/145/1 253/232/1 +f 116/142/1 248/236/1 250/234/1 +f 249/237/1 117/143/1 251/235/1 +f 118/140/1 246/238/1 248/236/1 +f 247/239/1 119/141/1 249/237/1 +f 120/138/1 244/240/1 246/238/1 +f 245/241/1 121/139/1 247/239/1 +f 122/136/1 242/242/1 244/240/1 +f 243/243/1 123/137/1 245/241/1 +f 124/133/1 240/244/1 242/242/1 +f 241/245/1 125/134/1 243/243/1 +f 126/132/1 236/246/1 240/244/1 +f 237/247/1 127/135/1 241/245/1 +f 179/130/1 238/248/1 236/246/1 +f 239/249/1 180/131/1 237/247/1 +f 128/127/1 256/228/1 238/248/1 +f 257/229/1 129/129/1 239/249/1 +f 238/248/1 258/250/1 276/251/1 +f 259/252/1 239/249/1 277/253/1 +f 236/246/1 276/251/1 278/254/1 +f 277/253/1 237/247/1 279/255/1 +f 240/244/1 278/254/1 274/256/1 +f 279/255/1 241/245/1 275/257/1 +f 242/242/1 274/256/1 272/258/1 +f 275/257/1 243/243/1 273/259/1 +f 244/240/1 272/258/1 270/260/1 +f 273/259/1 245/241/1 271/261/1 +f 246/238/1 270/260/1 268/262/1 +f 271/261/1 247/239/1 269/263/1 +f 248/236/1 268/262/1 266/264/1 +f 269/263/1 249/237/1 267/265/1 +f 250/234/1 266/264/1 264/266/1 +f 267/265/1 251/235/1 265/267/1 +f 252/231/1 264/266/1 262/268/1 +f 265/267/1 253/232/1 263/269/1 +f 234/222/1 262/268/1 280/270/1 +f 263/269/1 235/224/1 281/271/1 +f 256/228/1 260/272/1 258/250/1 +f 261/273/1 257/229/1 259/252/1 +f 254/226/1 282/274/1 260/272/1 +f 283/275/1 255/227/1 261/273/1 +f 232/223/1 280/270/1 282/274/1 +f 281/271/1 233/225/1 283/275/1 +f 67/124/1 284/276/1 73/277/1 +f 285/278/1 67/124/1 73/277/1 +f 108/120/1 286/279/1 284/276/1 +f 287/280/1 109/122/1 285/278/1 +f 106/116/1 288/281/1 286/279/1 +f 289/282/1 107/118/1 287/280/1 +f 104/117/1 290/283/1 288/281/1 +f 291/284/1 105/285/1 289/282/1 +f 102/112/1 292/286/1 290/283/1 +f 293/287/1 103/115/1 291/284/1 +f 100/108/1 294/288/1 292/286/1 +f 295/289/1 101/111/1 293/287/1 +f 98/104/1 296/290/1 294/288/1 +f 297/291/1 99/107/1 295/289/1 +f 96/100/1 298/292/1 296/290/1 +f 299/293/1 97/103/1 297/291/1 +f 94/96/1 300/294/1 298/292/1 +f 301/295/1 95/99/1 299/293/1 +f 308/296/1 328/297/1 338/298/1 +f 329/299/1 308/300/1 339/301/1 +f 307/302/1 338/298/1 336/303/1 +f 339/301/1 307/302/1 337/304/1 +f 306/305/1 336/303/1 340/306/1 +f 337/304/1 306/305/1 341/307/1 +f 89/66/1 306/305/1 340/306/1 +f 306/305/1 90/69/1 341/307/1 +f 87/70/1 340/306/1 334/308/1 +f 341/307/1 88/73/1 335/309/1 +f 85/74/1 334/308/1 330/310/1 +f 335/309/1 86/77/1 331/311/1 +f 83/78/1 330/310/1 332/312/1 +f 331/311/1 84/81/1 333/313/1 +f 330/310/1 338/298/1 332/312/1 +f 339/301/1 331/311/1 333/313/1 +f 330/310/1 340/306/1 336/303/1 +f 341/307/1 331/311/1 337/304/1 +f 326/314/1 338/298/1 328/297/1 +f 339/301/1 327/315/1 329/299/1 +f 81/82/1 332/312/1 326/314/1 +f 333/313/1 82/85/1 327/315/1 +f 209/201/1 344/316/1 215/203/1 +f 345/317/1 210/202/1 216/204/1 +f 81/82/1 342/318/1 209/201/1 +f 343/319/1 82/85/1 210/202/1 +f 79/86/1 344/316/1 346/320/1 +f 345/317/1 80/90/1 347/321/1 +f 79/86/1 300/294/1 92/92/1 +f 301/295/1 80/90/1 93/95/1 +f 77/322/1 352/323/1 304/324/1 +f 353/325/1 77/326/1 304/327/1 +f 304/324/1 350/328/1 78/329/1 +f 351/330/1 304/327/1 78/331/1 +f 78/329/3 348/332/3 305/333/3 +f 349/334/2 78/331/2 305/335/2 +f 305/333/1 328/297/1 309/336/1 +f 329/299/1 305/335/1 309/337/1 +f 326/314/1 348/332/1 342/318/1 +f 349/334/1 327/315/1 343/319/1 +f 296/290/1 318/338/1 310/339/1 +f 319/340/1 297/291/1 311/341/1 +f 76/342/1 324/343/1 77/322/1 +f 325/344/1 76/345/1 77/326/1 +f 302/346/1 356/347/1 303/348/1 +f 357/349/1 302/350/1 303/351/1 +f 356/347/3 75/352/3 303/348/3 +f 357/349/2 75/353/2 355/354/2 +f 75/352/1 316/355/1 76/342/1 +f 317/356/1 75/353/1 76/345/1 +f 292/357/1 362/358/1 364/359/1 +f 363/360/1 293/361/1 365/362/1 +f 364/359/1 368/363/1 366/364/1 +f 369/365/1 365/362/1 367/366/1 +f 366/364/3 370/367/3 372/368/3 +f 371/369/2 367/366/2 373/370/2 +f 370/367/3 374/371/3 372/368/3 +f 371/369/2 375/372/2 377/373/2 +f 314/374/1 374/371/1 376/375/1 +f 375/372/1 315/376/1 377/373/1 +f 316/355/1 374/371/1 378/377/1 +f 375/372/1 317/356/1 379/378/1 +f 354/379/1 372/368/1 374/371/1 +f 373/370/1 355/354/1 375/372/1 +f 358/380/3 372/368/3 356/347/3 +f 359/381/2 373/370/2 367/366/2 +f 358/380/1 364/359/1 366/364/1 +f 365/362/1 359/381/1 367/366/1 +f 290/382/1 364/359/1 360/383/1 +f 365/362/1 291/384/1 361/385/1 +f 74/386/1 358/380/1 302/346/1 +f 359/381/1 74/387/1 302/350/1 +f 284/388/1 288/389/1 290/382/1 +f 289/390/1 285/391/1 291/384/1 +f 284/388/1 360/383/1 74/386/1 +f 361/385/1 285/391/1 74/387/1 +f 73/392/1 284/388/1 74/386/1 +f 74/387/1 285/391/1 73/393/1 +f 294/288/1 310/339/1 362/358/1 +f 311/341/1 295/289/1 363/360/1 +f 310/339/1 368/363/1 362/358/1 +f 369/365/1 311/341/1 363/360/1 +f 382/394/3 368/363/3 312/395/3 +f 383/396/2 369/365/2 371/369/2 +f 376/375/1 382/394/1 314/374/1 +f 377/373/2 383/396/2 371/369/2 +f 350/328/3 384/397/3 348/332/3 +f 351/330/2 385/398/2 387/399/2 +f 384/397/1 320/400/1 318/338/1 +f 385/398/2 321/401/2 387/399/2 +f 298/292/1 384/397/1 318/338/1 +f 385/398/1 299/293/1 319/340/1 +f 300/294/1 342/318/1 384/397/1 +f 343/319/1 301/295/1 385/398/1 +f 342/318/1 348/332/1 384/397/1 +f 385/398/1 349/334/1 343/319/1 +f 300/294/1 346/320/1 344/316/1 +f 345/317/1 347/321/1 301/295/1 +f 314/374/1 380/402/1 378/377/1 +f 381/403/1 315/376/1 379/378/1 +f 316/355/1 380/402/1 324/343/1 +f 381/403/1 317/356/1 325/344/1 +f 386/404/3 322/405/3 320/400/3 +f 387/399/1 323/406/1 381/403/1 +f 350/328/1 380/402/1 386/404/1 +f 381/403/1 351/330/1 387/399/1 +f 324/343/1 380/402/1 352/323/1 +f 353/325/1 381/403/1 325/344/1 +f 400/407/1 414/408/1 402/409/1 +f 415/410/1 401/411/1 403/412/1 +f 400/407/1 404/413/1 398/414/1 +f 405/415/1 401/411/1 399/416/1 +f 398/414/1 406/417/1 396/418/1 +f 407/419/1 399/416/1 397/420/1 +f 396/418/1 408/421/1 394/422/1 +f 409/423/1 397/420/1 395/424/1 +f 394/422/1 410/425/1 392/426/1 +f 411/427/1 395/424/1 393/428/1 +f 392/426/3 412/429/3 390/430/3 +f 413/431/2 393/428/2 391/432/2 +f 410/425/3 418/433/3 412/429/3 +f 419/434/2 411/427/2 413/431/2 +f 408/421/1 420/435/1 410/425/1 +f 421/436/1 409/423/1 411/427/1 +f 406/417/1 422/437/1 408/421/1 +f 423/438/1 407/419/1 409/423/1 +f 404/413/1 424/439/1 406/417/1 +f 425/440/1 405/415/1 407/419/1 +f 402/409/1 426/441/1 404/413/1 +f 427/442/1 403/412/1 405/415/1 +f 402/409/1 416/443/1 428/444/1 +f 417/445/1 403/412/1 429/446/1 +f 318/338/1 444/447/1 442/448/1 +f 445/449/1 319/340/1 443/450/1 +f 320/451/1 412/429/1 444/452/1 +f 413/431/1 321/453/1 445/454/1 +f 310/339/1 442/448/1 312/395/1 +f 443/450/1 311/341/1 313/455/1 +f 382/456/1 414/408/1 388/457/1 +f 415/410/1 383/458/1 389/459/1 +f 418/433/3 444/452/3 412/429/3 +f 419/434/2 445/454/2 441/460/2 +f 438/461/3 444/452/3 440/462/3 +f 445/454/2 439/463/2 441/460/2 +f 434/464/1 438/461/1 436/465/1 +f 439/463/1 435/466/1 437/467/1 +f 432/468/1 446/469/1 434/464/1 +f 447/470/1 433/471/1 435/466/1 +f 430/472/1 432/468/1 450/473/1 +f 433/471/1 431/474/1 451/475/1 +f 414/408/1 450/473/1 416/443/1 +f 451/475/1 415/410/1 417/445/1 +f 312/395/3 430/476/3 382/394/3 +f 431/477/2 313/455/2 383/396/2 +f 442/448/3 448/478/3 312/395/3 +f 443/450/2 449/479/2 447/480/2 +f 442/448/3 444/447/3 446/481/3 +f 447/480/2 445/449/2 443/450/2 +f 416/443/1 452/482/1 476/483/1 +f 453/484/1 417/445/1 477/485/1 +f 450/473/1 462/486/1 452/482/1 +f 463/487/1 451/475/1 453/484/1 +f 432/468/1 460/488/1 462/486/1 +f 461/489/1 433/471/1 463/487/1 +f 434/464/1 458/490/1 460/488/1 +f 459/491/1 435/466/1 461/489/1 +f 436/465/1 456/492/1 458/490/1 +f 457/493/1 437/467/1 459/491/1 +f 438/461/1 454/494/1 456/492/1 +f 455/495/1 439/463/1 457/493/1 +f 440/462/1 474/496/1 454/494/1 +f 475/497/1 441/460/1 455/495/1 +f 428/444/1 476/483/1 464/498/1 +f 477/485/1 429/446/1 465/499/1 +f 426/441/1 464/498/1 466/500/1 +f 465/499/1 427/442/1 467/501/1 +f 424/439/1 466/500/1 468/502/1 +f 467/501/1 425/440/1 469/503/1 +f 422/437/1 468/502/1 470/504/1 +f 469/503/1 423/438/1 471/505/1 +f 420/435/1 470/504/1 472/506/1 +f 471/505/1 421/436/1 473/507/1 +f 418/433/1 472/506/1 474/496/1 +f 473/507/1 419/434/1 475/497/1 +f 458/490/1 480/508/1 478/509/1 +f 481/510/1 459/491/1 479/511/1 +f 478/509/1 482/512/1 484/513/1 +f 483/514/1 479/511/1 485/515/1 +f 484/513/1 488/516/1 486/517/1 +f 489/518/1 485/515/1 487/519/1 +f 486/517/1 490/520/1 492/521/1 +f 491/522/1 487/519/1 493/523/1 +f 464/498/1 486/517/1 492/521/1 +f 487/519/1 465/499/1 493/523/1 +f 452/482/1 486/517/1 476/483/1 +f 487/519/1 453/484/1 477/485/1 +f 452/482/1 478/509/1 484/513/1 +f 479/511/1 453/484/1 485/515/1 +f 458/490/1 462/486/1 460/488/1 +f 463/487/1 459/491/1 461/489/1 +f 454/494/1 480/508/1 456/492/1 +f 481/510/1 455/495/1 457/493/1 +f 472/506/1 480/508/1 474/496/1 +f 481/510/1 473/507/1 475/497/1 +f 470/504/1 482/512/1 472/506/1 +f 483/514/1 471/505/1 473/507/1 +f 468/502/1 488/516/1 470/504/1 +f 489/518/1 469/503/1 471/505/1 +f 466/500/1 490/520/1 468/502/1 +f 491/522/1 467/501/1 469/503/1 +f 464/498/1 492/521/1 466/500/1 +f 467/501/1 493/523/1 465/499/1 +f 392/426/1 504/524/1 502/525/1 +f 505/526/1 393/428/1 503/527/1 +f 394/422/1 502/525/1 500/528/1 +f 503/527/1 395/424/1 501/529/1 +f 396/418/1 500/528/1 498/530/1 +f 501/529/1 397/420/1 499/531/1 +f 398/532/1 498/530/1 496/533/1 +f 499/531/1 399/534/1 497/535/1 +f 400/536/1 496/533/1 494/537/1 +f 497/535/1 401/538/1 495/539/1 +f 388/540/1 494/537/1 506/541/1 +f 495/539/1 389/542/1 507/543/1 +f 494/537/1 504/524/1 506/541/1 +f 505/526/1 495/539/1 507/543/1 +f 494/537/1 500/528/1 502/525/1 +f 501/529/1 495/539/1 503/527/1 +f 496/533/1 498/530/1 500/528/1 +f 501/529/1 499/531/1 497/535/1 +f 314/374/1 388/544/1 506/545/1 +f 389/542/1 315/546/1 507/543/1 +f 314/547/1 504/524/1 322/548/1 +f 505/526/1 315/546/1 323/549/1 +f 320/451/2 504/524/2 390/430/2 +f 505/526/3 321/453/3 391/432/3 +f 47/1/1 1/12/1 3/2/1 +f 4/4/1 2/15/1 48/5/1 +f 45/3/1 3/2/1 5/7/1 +f 6/9/1 4/4/1 46/6/1 +f 3/2/1 9/13/1 7/10/1 +f 8/11/1 10/14/1 4/4/1 +f 1/12/1 11/16/1 9/13/1 +f 10/14/1 12/19/1 2/15/1 +f 11/16/1 13/24/1 15/17/1 +f 16/18/1 14/27/1 12/19/1 +f 9/13/1 15/17/1 17/20/1 +f 18/21/1 16/18/1 10/14/1 +f 15/17/1 21/25/1 19/22/1 +f 20/23/1 22/26/1 16/18/1 +f 13/24/1 23/28/1 21/25/1 +f 22/26/1 24/31/1 14/27/1 +f 23/28/1 25/36/1 27/29/1 +f 28/30/1 26/39/1 24/31/1 +f 21/25/1 27/29/1 29/32/1 +f 30/33/1 28/30/1 22/26/1 +f 27/29/1 33/37/1 31/34/1 +f 32/35/1 34/38/1 28/30/1 +f 25/36/1 35/40/1 33/37/1 +f 34/38/1 36/43/1 26/39/1 +f 35/40/1 37/46/1 39/41/1 +f 40/42/1 38/47/1 36/43/1 +f 33/37/1 39/41/1 41/44/1 +f 42/45/1 40/42/1 34/38/1 +f 39/41/1 45/3/1 43/8/1 +f 44/9/1 46/6/1 40/42/1 +f 37/46/1 47/1/1 45/3/1 +f 46/6/1 48/5/1 38/47/1 +f 47/1/1 37/46/1 51/48/1 +f 52/50/1 38/47/1 48/5/1 +f 37/46/1 35/40/1 53/52/1 +f 54/53/1 36/43/1 38/47/1 +f 35/40/1 25/36/1 55/54/1 +f 56/55/1 26/39/1 36/43/1 +f 25/36/1 23/28/1 57/56/1 +f 58/57/1 24/31/1 26/39/1 +f 23/28/1 13/24/1 59/58/1 +f 60/59/1 14/27/1 24/31/1 +f 13/24/1 11/16/1 63/60/1 +f 64/61/1 12/19/1 14/27/1 +f 11/16/1 1/12/1 65/62/1 +f 66/63/1 2/15/1 12/19/1 +f 1/12/1 47/1/1 49/49/1 +f 50/51/1 48/5/1 2/15/1 +f 89/66/1 174/71/1 176/67/1 +f 176/67/1 175/72/1 90/69/1 +f 87/70/1 172/75/1 174/71/1 +f 175/72/1 173/76/1 88/73/1 +f 85/74/1 170/79/1 172/75/1 +f 173/76/1 171/80/1 86/77/1 +f 83/78/1 168/83/1 170/79/1 +f 171/80/1 169/84/1 84/81/1 +f 81/82/1 166/159/1 168/83/1 +f 169/84/1 167/162/1 82/85/1 +f 79/86/1 92/92/1 146/87/1 +f 147/89/1 93/95/1 80/90/1 +f 92/92/1 94/96/1 148/93/1 +f 149/94/1 95/99/1 93/95/1 +f 94/96/1 96/100/1 150/97/1 +f 151/98/1 97/103/1 95/99/1 +f 96/100/1 98/104/1 152/101/1 +f 153/102/1 99/107/1 97/103/1 +f 98/104/1 100/108/1 154/105/1 +f 155/106/1 101/111/1 99/107/1 +f 100/108/1 102/112/1 156/109/1 +f 157/110/1 103/115/1 101/111/1 +f 102/112/2 104/117/2 158/113/2 +f 159/114/3 105/285/3 103/115/3 +f 106/116/3 160/121/3 158/113/3 +f 107/118/2 105/285/2 159/114/2 +f 108/120/3 162/125/3 160/121/3 +f 109/122/2 107/118/2 161/119/2 +f 67/124/3 68/126/3 162/125/3 +f 67/124/2 109/122/2 163/123/2 +f 128/127/2 160/121/2 162/125/2 +f 129/129/3 111/148/3 163/123/3 +f 179/130/2 158/113/2 160/121/2 +f 180/131/3 129/129/3 161/119/3 +f 156/109/2 158/113/2 179/130/2 +f 157/110/1 127/135/1 180/131/1 +f 124/133/1 154/105/1 156/109/1 +f 157/110/1 155/106/1 125/134/1 +f 122/136/1 152/101/1 154/105/1 +f 155/106/1 153/102/1 123/137/1 +f 120/138/1 150/97/1 152/101/1 +f 153/102/1 151/98/1 121/139/1 +f 118/140/1 148/93/1 150/97/1 +f 151/98/1 149/94/1 119/141/1 +f 116/142/1 146/87/1 148/93/1 +f 149/94/1 147/89/1 117/143/1 +f 114/144/1 164/88/1 146/87/1 +f 147/89/1 165/91/1 115/145/1 +f 114/144/1 181/230/1 177/146/1 +f 177/146/1 182/233/1 115/145/1 +f 110/128/2 162/125/2 68/126/2 +f 68/126/3 163/123/3 111/148/3 +f 112/147/1 68/126/1 178/150/1 +f 178/150/1 68/126/1 113/149/1 +f 177/146/1 181/230/1 183/151/1 +f 184/152/1 182/233/1 177/146/1 +f 135/153/1 137/212/1 176/67/1 +f 176/67/1 137/212/1 136/154/1 +f 133/155/1 135/153/1 174/71/1 +f 175/72/1 136/154/1 134/156/1 +f 131/157/1 133/155/1 172/75/1 +f 173/76/1 134/156/1 132/158/1 +f 166/159/1 187/165/1 185/160/1 +f 186/161/1 188/167/1 167/162/1 +f 131/157/1 170/79/1 168/83/1 +f 169/84/1 171/80/1 132/158/1 +f 144/163/1 190/184/1 189/164/1 +f 189/164/1 190/184/1 145/166/1 +f 185/160/1 187/165/1 189/164/1 +f 189/164/1 188/167/1 186/161/1 +f 130/169/1 131/157/1 185/160/1 +f 186/161/1 132/158/1 130/169/1 +f 142/170/1 193/175/1 191/171/1 +f 192/172/1 194/176/1 143/173/1 +f 140/174/1 195/179/1 193/175/1 +f 194/176/1 196/180/1 141/177/1 +f 139/178/1 197/182/1 195/179/1 +f 196/180/1 198/183/1 139/178/1 +f 138/181/1 71/189/1 197/182/1 +f 198/183/1 71/189/1 138/181/1 +f 190/184/1 144/163/1 191/171/1 +f 192/172/1 145/166/1 190/184/1 +f 70/185/1 191/171/1 206/186/1 +f 207/188/1 192/172/1 70/185/1 +f 71/189/3 199/195/3 200/190/3 +f 201/191/2 199/195/2 71/189/2 +f 197/182/1 200/190/1 202/192/1 +f 203/193/1 201/191/1 198/183/1 +f 202/192/2 204/196/2 193/175/2 +f 203/193/1 196/180/1 194/176/1 +f 193/175/2 204/196/2 206/186/2 +f 207/188/3 205/194/3 194/176/3 +f 199/195/2 204/196/2 202/192/2 +f 203/193/3 205/194/3 199/195/3 +f 199/195/2 208/187/2 206/186/2 +f 207/188/3 208/187/3 199/195/3 +f 139/178/1 140/174/1 164/88/1 +f 165/91/1 141/177/1 139/178/1 +f 140/174/1 142/170/1 211/197/1 +f 212/198/1 143/173/1 141/177/1 +f 142/170/1 144/163/1 213/199/1 +f 214/200/1 145/166/1 143/173/1 +f 144/163/1 187/165/1 166/159/1 +f 167/162/1 188/167/1 145/166/1 +f 81/82/1 209/201/1 213/199/1 +f 214/200/1 210/202/1 82/85/1 +f 209/201/1 215/203/1 211/197/1 +f 212/198/1 216/204/1 210/202/1 +f 79/86/1 164/88/1 211/197/1 +f 212/198/1 165/91/1 80/90/1 +f 131/157/1 130/169/1 72/205/1 +f 72/205/1 130/169/1 132/158/1 +f 133/155/1 131/157/1 222/206/1 +f 223/207/1 132/158/1 134/156/1 +f 135/153/1 133/155/1 220/208/1 +f 221/209/1 134/156/1 136/154/1 +f 137/212/1 135/153/1 218/210/1 +f 219/211/1 136/154/1 137/212/1 +f 217/213/1 218/210/1 229/214/1 +f 230/216/1 219/211/1 217/213/1 +f 218/210/1 220/208/1 227/217/1 +f 228/218/1 221/209/1 219/211/1 +f 220/208/1 222/206/1 225/219/1 +f 226/220/1 223/207/1 221/209/1 +f 222/206/1 72/205/1 224/221/1 +f 224/221/1 72/205/1 223/207/1 +f 224/221/1 231/215/1 229/214/1 +f 230/216/1 231/215/1 224/221/1 +f 183/151/1 181/230/1 234/222/1 +f 235/224/1 182/233/1 184/152/1 +f 112/147/1 183/151/1 232/223/1 +f 233/225/1 184/152/1 113/149/1 +f 110/128/1 112/147/1 254/226/1 +f 255/227/1 113/149/1 111/148/1 +f 181/230/1 114/144/1 252/231/1 +f 253/232/1 115/145/1 182/233/1 +f 114/144/1 116/142/1 250/234/1 +f 251/235/1 117/143/1 115/145/1 +f 116/142/1 118/140/1 248/236/1 +f 249/237/1 119/141/1 117/143/1 +f 118/140/1 120/138/1 246/238/1 +f 247/239/1 121/139/1 119/141/1 +f 120/138/1 122/136/1 244/240/1 +f 245/241/1 123/137/1 121/139/1 +f 122/136/1 124/133/1 242/242/1 +f 243/243/1 125/134/1 123/137/1 +f 124/133/1 126/132/1 240/244/1 +f 241/245/1 127/135/1 125/134/1 +f 126/132/1 179/130/1 236/246/1 +f 237/247/1 180/131/1 127/135/1 +f 179/130/1 128/127/1 238/248/1 +f 239/249/1 129/129/1 180/131/1 +f 128/127/1 110/128/1 256/228/1 +f 257/229/1 111/148/1 129/129/1 +f 238/248/1 256/228/1 258/250/1 +f 259/252/1 257/229/1 239/249/1 +f 236/246/1 238/248/1 276/251/1 +f 277/253/1 239/249/1 237/247/1 +f 240/244/1 236/246/1 278/254/1 +f 279/255/1 237/247/1 241/245/1 +f 242/242/1 240/244/1 274/256/1 +f 275/257/1 241/245/1 243/243/1 +f 244/240/1 242/242/1 272/258/1 +f 273/259/1 243/243/1 245/241/1 +f 246/238/1 244/240/1 270/260/1 +f 271/261/1 245/241/1 247/239/1 +f 248/236/1 246/238/1 268/262/1 +f 269/263/1 247/239/1 249/237/1 +f 250/234/1 248/236/1 266/264/1 +f 267/265/1 249/237/1 251/235/1 +f 252/231/1 250/234/1 264/266/1 +f 265/267/1 251/235/1 253/232/1 +f 234/222/1 252/231/1 262/268/1 +f 263/269/1 253/232/1 235/224/1 +f 256/228/1 254/226/1 260/272/1 +f 261/273/1 255/227/1 257/229/1 +f 254/226/1 232/223/1 282/274/1 +f 283/275/1 233/225/1 255/227/1 +f 232/223/1 234/222/1 280/270/1 +f 281/271/1 235/224/1 233/225/1 +f 67/124/1 108/120/1 284/276/1 +f 285/278/1 109/122/1 67/124/1 +f 108/120/1 106/116/1 286/279/1 +f 287/280/1 107/118/1 109/122/1 +f 106/116/1 104/117/1 288/281/1 +f 289/282/1 105/285/1 107/118/1 +f 104/117/1 102/112/1 290/283/1 +f 291/284/1 103/115/1 105/285/1 +f 102/112/1 100/108/1 292/286/1 +f 293/287/1 101/111/1 103/115/1 +f 100/108/1 98/104/1 294/288/1 +f 295/289/1 99/107/1 101/111/1 +f 98/104/1 96/100/1 296/290/1 +f 297/291/1 97/103/1 99/107/1 +f 96/100/1 94/96/1 298/292/1 +f 299/293/1 95/99/1 97/103/1 +f 94/96/1 92/92/1 300/294/1 +f 301/295/1 93/95/1 95/99/1 +f 308/296/1 309/336/1 328/297/1 +f 329/299/1 309/337/1 308/300/1 +f 307/302/1 308/296/1 338/298/1 +f 339/301/1 308/300/1 307/302/1 +f 306/305/1 307/302/1 336/303/1 +f 337/304/1 307/302/1 306/305/1 +f 89/66/1 91/68/1 306/305/1 +f 306/305/1 91/68/1 90/69/1 +f 87/70/1 89/66/1 340/306/1 +f 341/307/1 90/69/1 88/73/1 +f 85/74/1 87/70/1 334/308/1 +f 335/309/1 88/73/1 86/77/1 +f 83/78/1 85/74/1 330/310/1 +f 331/311/1 86/77/1 84/81/1 +f 330/310/1 336/303/1 338/298/1 +f 339/301/1 337/304/1 331/311/1 +f 330/310/1 334/308/1 340/306/1 +f 341/307/1 335/309/1 331/311/1 +f 326/314/1 332/312/1 338/298/1 +f 339/301/1 333/313/1 327/315/1 +f 81/82/1 83/78/1 332/312/1 +f 333/313/1 84/81/1 82/85/1 +f 209/201/1 342/318/1 344/316/1 +f 345/317/1 343/319/1 210/202/1 +f 81/82/1 326/314/1 342/318/1 +f 343/319/1 327/315/1 82/85/1 +f 79/86/1 215/203/1 344/316/1 +f 345/317/1 216/204/1 80/90/1 +f 79/86/1 346/320/1 300/294/1 +f 301/295/1 347/321/1 80/90/1 +f 77/322/1 324/343/1 352/323/1 +f 353/325/1 325/344/1 77/326/1 +f 304/324/1 352/323/1 350/328/1 +f 351/330/1 353/325/1 304/327/1 +f 78/329/3 350/328/3 348/332/3 +f 349/334/2 351/330/2 78/331/2 +f 305/333/1 348/332/1 328/297/1 +f 329/299/1 349/334/1 305/335/1 +f 326/314/1 328/297/1 348/332/1 +f 349/334/1 329/299/1 327/315/1 +f 296/290/1 298/292/1 318/338/1 +f 319/340/1 299/293/1 297/291/1 +f 76/342/1 316/355/1 324/343/1 +f 325/344/1 317/356/1 76/345/1 +f 302/346/1 358/380/1 356/347/1 +f 357/349/1 359/381/1 302/350/1 +f 356/347/3 354/379/3 75/352/3 +f 357/349/2 303/351/2 75/353/2 +f 75/352/1 354/379/1 316/355/1 +f 317/356/1 355/354/1 75/353/1 +f 292/357/1 294/288/1 362/358/1 +f 363/360/1 295/289/1 293/361/1 +f 364/359/1 362/358/1 368/363/1 +f 369/365/1 363/360/1 365/362/1 +f 366/364/1 368/363/1 370/367/1 +f 371/369/1 369/365/1 367/366/1 +f 370/367/3 376/375/3 374/371/3 +f 371/369/2 373/370/2 375/372/2 +f 314/374/1 378/377/1 374/371/1 +f 375/372/1 379/378/1 315/376/1 +f 316/355/1 354/379/1 374/371/1 +f 375/372/1 355/354/1 317/356/1 +f 354/379/3 356/347/3 372/368/3 +f 373/370/2 357/349/2 355/354/2 +f 358/380/3 366/364/3 372/368/3 +f 359/381/2 357/349/2 373/370/2 +f 358/380/1 360/383/1 364/359/1 +f 365/362/1 361/385/1 359/381/1 +f 290/382/1 292/357/1 364/359/1 +f 365/362/1 293/361/1 291/384/1 +f 74/386/1 360/383/1 358/380/1 +f 359/381/1 361/385/1 74/387/1 +f 284/388/1 286/550/1 288/389/1 +f 289/390/1 287/551/1 285/391/1 +f 284/388/1 290/382/1 360/383/1 +f 361/385/1 291/384/1 285/391/1 +f 294/288/1 296/290/1 310/339/1 +f 311/341/1 297/291/1 295/289/1 +f 310/339/1 312/395/1 368/363/1 +f 369/365/1 313/455/1 311/341/1 +f 382/394/3 370/367/3 368/363/3 +f 383/396/2 313/455/2 369/365/2 +f 376/375/3 370/367/3 382/394/3 +f 377/373/1 315/376/1 383/396/1 +f 350/328/3 386/404/3 384/397/3 +f 351/330/2 349/334/2 385/398/2 +f 384/397/3 386/404/3 320/400/3 +f 385/398/1 319/340/1 321/401/1 +f 298/292/1 300/294/1 384/397/1 +f 385/398/1 301/295/1 299/293/1 +f 300/294/1 344/316/1 342/318/1 +f 343/319/1 345/317/1 301/295/1 +f 314/374/1 322/405/1 380/402/1 +f 381/403/1 323/406/1 315/376/1 +f 316/355/1 378/377/1 380/402/1 +f 381/403/1 379/378/1 317/356/1 +f 386/404/1 380/402/1 322/405/1 +f 387/399/2 321/401/2 323/406/2 +f 350/328/1 352/323/1 380/402/1 +f 381/403/1 353/325/1 351/330/1 +f 400/407/1 388/457/1 414/408/1 +f 415/410/1 389/459/1 401/411/1 +f 400/407/1 402/409/1 404/413/1 +f 405/415/1 403/412/1 401/411/1 +f 398/414/1 404/413/1 406/417/1 +f 407/419/1 405/415/1 399/416/1 +f 396/418/1 406/417/1 408/421/1 +f 409/423/1 407/419/1 397/420/1 +f 394/422/1 408/421/1 410/425/1 +f 411/427/1 409/423/1 395/424/1 +f 392/426/3 410/425/3 412/429/3 +f 413/431/2 411/427/2 393/428/2 +f 410/425/1 420/435/1 418/433/1 +f 419/434/1 421/436/1 411/427/1 +f 408/421/1 422/437/1 420/435/1 +f 421/436/1 423/438/1 409/423/1 +f 406/417/1 424/439/1 422/437/1 +f 423/438/1 425/440/1 407/419/1 +f 404/413/1 426/441/1 424/439/1 +f 425/440/1 427/442/1 405/415/1 +f 402/409/1 428/444/1 426/441/1 +f 427/442/1 429/446/1 403/412/1 +f 402/409/1 414/408/1 416/443/1 +f 417/445/1 415/410/1 403/412/1 +f 318/338/1 320/400/1 444/447/1 +f 445/449/1 321/401/1 319/340/1 +f 320/451/1 390/430/1 412/429/1 +f 413/431/1 391/432/1 321/453/1 +f 310/339/1 318/338/1 442/448/1 +f 443/450/1 319/340/1 311/341/1 +f 382/456/1 430/472/1 414/408/1 +f 415/410/1 431/474/1 383/458/1 +f 418/433/3 440/462/3 444/452/3 +f 419/434/2 413/431/2 445/454/2 +f 438/461/3 446/469/3 444/452/3 +f 445/454/2 447/470/2 439/463/2 +f 434/464/1 446/469/1 438/461/1 +f 439/463/1 447/470/1 435/466/1 +f 432/468/1 448/552/1 446/469/1 +f 447/470/1 449/553/1 433/471/1 +f 430/472/1 448/552/1 432/468/1 +f 433/471/1 449/553/1 431/474/1 +f 414/408/1 430/472/1 450/473/1 +f 451/475/1 431/474/1 415/410/1 +f 312/395/3 448/478/3 430/476/3 +f 431/477/2 449/479/2 313/455/2 +f 442/448/3 446/481/3 448/478/3 +f 443/450/2 313/455/2 449/479/2 +f 416/443/1 450/473/1 452/482/1 +f 453/484/1 451/475/1 417/445/1 +f 450/473/1 432/468/1 462/486/1 +f 463/487/1 433/471/1 451/475/1 +f 432/468/1 434/464/1 460/488/1 +f 461/489/1 435/466/1 433/471/1 +f 434/464/1 436/465/1 458/490/1 +f 459/491/1 437/467/1 435/466/1 +f 436/465/1 438/461/1 456/492/1 +f 457/493/1 439/463/1 437/467/1 +f 438/461/1 440/462/1 454/494/1 +f 455/495/1 441/460/1 439/463/1 +f 440/462/1 418/433/1 474/496/1 +f 475/497/1 419/434/1 441/460/1 +f 428/444/1 416/443/1 476/483/1 +f 477/485/1 417/445/1 429/446/1 +f 426/441/1 428/444/1 464/498/1 +f 465/499/1 429/446/1 427/442/1 +f 424/439/1 426/441/1 466/500/1 +f 467/501/1 427/442/1 425/440/1 +f 422/437/1 424/439/1 468/502/1 +f 469/503/1 425/440/1 423/438/1 +f 420/435/1 422/437/1 470/504/1 +f 471/505/1 423/438/1 421/436/1 +f 418/433/1 420/435/1 472/506/1 +f 473/507/1 421/436/1 419/434/1 +f 458/490/1 456/492/1 480/508/1 +f 481/510/1 457/493/1 459/491/1 +f 478/509/1 480/508/1 482/512/1 +f 483/514/1 481/510/1 479/511/1 +f 484/513/1 482/512/1 488/516/1 +f 489/518/1 483/514/1 485/515/1 +f 486/517/1 488/516/1 490/520/1 +f 491/522/1 489/518/1 487/519/1 +f 464/498/1 476/483/1 486/517/1 +f 487/519/1 477/485/1 465/499/1 +f 452/482/1 484/513/1 486/517/1 +f 487/519/1 485/515/1 453/484/1 +f 452/482/1 462/486/1 478/509/1 +f 479/511/1 463/487/1 453/484/1 +f 458/490/1 478/509/1 462/486/1 +f 463/487/1 479/511/1 459/491/1 +f 454/494/1 474/496/1 480/508/1 +f 481/510/1 475/497/1 455/495/1 +f 472/506/1 482/512/1 480/508/1 +f 481/510/1 483/514/1 473/507/1 +f 470/504/1 488/516/1 482/512/1 +f 483/514/1 489/518/1 471/505/1 +f 468/502/1 490/520/1 488/516/1 +f 489/518/1 491/522/1 469/503/1 +f 466/500/1 492/521/1 490/520/1 +f 491/522/1 493/523/1 467/501/1 +f 392/426/3 390/430/3 504/524/3 +f 505/526/2 391/432/2 393/428/2 +f 394/422/1 392/426/1 502/525/1 +f 503/527/1 393/428/1 395/424/1 +f 396/418/1 394/422/1 500/528/1 +f 501/529/1 395/424/1 397/420/1 +f 398/532/1 396/418/1 498/530/1 +f 499/531/1 397/420/1 399/534/1 +f 400/536/1 398/532/1 496/533/1 +f 497/535/1 399/534/1 401/538/1 +f 388/540/1 400/536/1 494/537/1 +f 495/539/1 401/538/1 389/542/1 +f 494/537/1 502/525/1 504/524/1 +f 505/526/1 503/527/1 495/539/1 +f 494/537/1 496/533/1 500/528/1 +f 501/529/1 497/535/1 495/539/1 +f 314/374/1 382/394/1 388/544/1 +f 389/542/1 383/554/1 315/546/1 +f 314/547/1 506/541/1 504/524/1 +f 505/526/1 507/543/1 315/546/1 +f 320/451/2 322/548/2 504/524/2 +f 505/526/3 323/549/3 321/453/3 diff --git a/crates/bevy_mikktspace/data/suzanne_flat_tris.bin b/crates/bevy_mikktspace/data/suzanne_flat_tris.bin new file mode 100644 index 0000000000000..33fb3138af902 Binary files /dev/null and b/crates/bevy_mikktspace/data/suzanne_flat_tris.bin differ diff --git a/crates/bevy_mikktspace/data/suzanne_flat_tris.obj b/crates/bevy_mikktspace/data/suzanne_flat_tris.obj new file mode 100644 index 0000000000000..f75ba799a01da --- /dev/null +++ b/crates/bevy_mikktspace/data/suzanne_flat_tris.obj @@ -0,0 +1,2066 @@ +# Blender 3.6.0 +# www.blender.org +o Suzanne +v 0.437500 0.164062 0.765625 +v -0.437500 0.164062 0.765625 +v 0.500000 0.093750 0.687500 +v -0.500000 0.093750 0.687500 +v 0.546875 0.054688 0.578125 +v -0.546875 0.054688 0.578125 +v 0.351562 -0.023438 0.617188 +v -0.351562 -0.023438 0.617188 +v 0.351562 0.031250 0.718750 +v -0.351562 0.031250 0.718750 +v 0.351562 0.132812 0.781250 +v -0.351562 0.132812 0.781250 +v 0.273438 0.164062 0.796875 +v -0.273438 0.164062 0.796875 +v 0.203125 0.093750 0.742188 +v -0.203125 0.093750 0.742188 +v 0.156250 0.054688 0.648438 +v -0.156250 0.054688 0.648438 +v 0.078125 0.242188 0.656250 +v -0.078125 0.242188 0.656250 +v 0.140625 0.242188 0.742188 +v -0.140625 0.242188 0.742188 +v 0.242188 0.242188 0.796875 +v -0.242188 0.242188 0.796875 +v 0.273438 0.328125 0.796875 +v -0.273438 0.328125 0.796875 +v 0.203125 0.390625 0.742188 +v -0.203125 0.390625 0.742188 +v 0.156250 0.437500 0.648438 +v -0.156250 0.437500 0.648438 +v 0.351562 0.515625 0.617188 +v -0.351562 0.515625 0.617188 +v 0.351562 0.453125 0.718750 +v -0.351562 0.453125 0.718750 +v 0.351562 0.359375 0.781250 +v -0.351562 0.359375 0.781250 +v 0.437500 0.328125 0.765625 +v -0.437500 0.328125 0.765625 +v 0.500000 0.390625 0.687500 +v -0.500000 0.390625 0.687500 +v 0.546875 0.437500 0.578125 +v -0.546875 0.437500 0.578125 +v 0.625000 0.242188 0.562500 +v -0.625000 0.242188 0.562500 +v 0.562500 0.242188 0.671875 +v -0.562500 0.242188 0.671875 +v 0.468750 0.242188 0.757812 +v -0.468750 0.242188 0.757812 +v 0.476562 0.242188 0.773438 +v -0.476562 0.242188 0.773438 +v 0.445312 0.335938 0.781250 +v -0.445312 0.335938 0.781250 +v 0.351562 0.375000 0.804688 +v -0.351562 0.375000 0.804688 +v 0.265625 0.335938 0.820312 +v -0.265625 0.335938 0.820312 +v 0.226562 0.242188 0.820312 +v -0.226562 0.242188 0.820312 +v 0.265625 0.156250 0.820312 +v -0.265625 0.156250 0.820312 +v 0.351562 0.242188 0.828125 +v -0.351562 0.242188 0.828125 +v 0.351562 0.117188 0.804688 +v -0.351562 0.117188 0.804688 +v 0.445312 0.156250 0.781250 +v -0.445312 0.156250 0.781250 +v 0.000000 0.429688 0.742188 +v 0.000000 0.351562 0.820312 +v 0.000000 -0.679688 0.734375 +v 0.000000 -0.320312 0.781250 +v 0.000000 -0.187500 0.796875 +v 0.000000 -0.773438 0.718750 +v 0.000000 0.406250 0.601562 +v 0.000000 0.570312 0.570312 +v 0.000000 0.898438 -0.546875 +v 0.000000 0.562500 -0.851562 +v 0.000000 0.070312 -0.828125 +v 0.000000 -0.382812 -0.351562 +v 0.203125 -0.187500 0.562500 +v -0.203125 -0.187500 0.562500 +v 0.312500 -0.437500 0.570312 +v -0.312500 -0.437500 0.570312 +v 0.351562 -0.695312 0.570312 +v -0.351562 -0.695312 0.570312 +v 0.367188 -0.890625 0.531250 +v -0.367188 -0.890625 0.531250 +v 0.328125 -0.945312 0.523438 +v -0.328125 -0.945312 0.523438 +v 0.179688 -0.968750 0.554688 +v -0.179688 -0.968750 0.554688 +v 0.000000 -0.984375 0.578125 +v 0.437500 -0.140625 0.531250 +v -0.437500 -0.140625 0.531250 +v 0.632812 -0.039062 0.539062 +v -0.632812 -0.039062 0.539062 +v 0.828125 0.148438 0.445312 +v -0.828125 0.148438 0.445312 +v 0.859375 0.429688 0.593750 +v -0.859375 0.429688 0.593750 +v 0.710938 0.484375 0.625000 +v -0.710938 0.484375 0.625000 +v 0.492188 0.601562 0.687500 +v -0.492188 0.601562 0.687500 +v 0.320312 0.757812 0.734375 +v -0.320312 0.757812 0.734375 +v 0.156250 0.718750 0.757812 +v -0.156250 0.718750 0.757812 +v 0.062500 0.492188 0.750000 +v -0.062500 0.492188 0.750000 +v 0.164062 0.414062 0.773438 +v -0.164062 0.414062 0.773438 +v 0.125000 0.304688 0.765625 +v -0.125000 0.304688 0.765625 +v 0.203125 0.093750 0.742188 +v -0.203125 0.093750 0.742188 +v 0.375000 0.015625 0.703125 +v -0.375000 0.015625 0.703125 +v 0.492188 0.062500 0.671875 +v -0.492188 0.062500 0.671875 +v 0.625000 0.187500 0.648438 +v -0.625000 0.187500 0.648438 +v 0.640625 0.296875 0.648438 +v -0.640625 0.296875 0.648438 +v 0.601562 0.375000 0.664062 +v -0.601562 0.375000 0.664062 +v 0.429688 0.437500 0.718750 +v -0.429688 0.437500 0.718750 +v 0.250000 0.468750 0.757812 +v -0.250000 0.468750 0.757812 +v 0.000000 -0.765625 0.734375 +v 0.109375 -0.718750 0.734375 +v -0.109375 -0.718750 0.734375 +v 0.117188 -0.835938 0.710938 +v -0.117188 -0.835938 0.710938 +v 0.062500 -0.882812 0.695312 +v -0.062500 -0.882812 0.695312 +v 0.000000 -0.890625 0.687500 +v 0.000000 -0.195312 0.750000 +v 0.000000 -0.140625 0.742188 +v 0.101562 -0.148438 0.742188 +v -0.101562 -0.148438 0.742188 +v 0.125000 -0.226562 0.750000 +v -0.125000 -0.226562 0.750000 +v 0.085938 -0.289062 0.742188 +v -0.085938 -0.289062 0.742188 +v 0.398438 -0.046875 0.671875 +v -0.398438 -0.046875 0.671875 +v 0.617188 0.054688 0.625000 +v -0.617188 0.054688 0.625000 +v 0.726562 0.203125 0.601562 +v -0.726562 0.203125 0.601562 +v 0.742188 0.375000 0.656250 +v -0.742188 0.375000 0.656250 +v 0.687500 0.414062 0.726562 +v -0.687500 0.414062 0.726562 +v 0.437500 0.546875 0.796875 +v -0.437500 0.546875 0.796875 +v 0.312500 0.640625 0.835938 +v -0.312500 0.640625 0.835938 +v 0.203125 0.617188 0.851562 +v -0.203125 0.617188 0.851562 +v 0.101562 0.429688 0.843750 +v -0.101562 0.429688 0.843750 +v 0.125000 -0.101562 0.812500 +v -0.125000 -0.101562 0.812500 +v 0.210938 -0.445312 0.710938 +v -0.210938 -0.445312 0.710938 +v 0.250000 -0.703125 0.687500 +v -0.250000 -0.703125 0.687500 +v 0.265625 -0.820312 0.664062 +v -0.265625 -0.820312 0.664062 +v 0.234375 -0.914062 0.632812 +v -0.234375 -0.914062 0.632812 +v 0.164062 -0.929688 0.632812 +v -0.164062 -0.929688 0.632812 +v 0.000000 -0.945312 0.640625 +v 0.000000 0.046875 0.726562 +v 0.000000 0.210938 0.765625 +v 0.328125 0.476562 0.742188 +v -0.328125 0.476562 0.742188 +v 0.164062 0.140625 0.750000 +v -0.164062 0.140625 0.750000 +v 0.132812 0.210938 0.757812 +v -0.132812 0.210938 0.757812 +v 0.117188 -0.687500 0.734375 +v -0.117188 -0.687500 0.734375 +v 0.078125 -0.445312 0.750000 +v -0.078125 -0.445312 0.750000 +v 0.000000 -0.445312 0.750000 +v 0.000000 -0.328125 0.742188 +v 0.093750 -0.273438 0.781250 +v -0.093750 -0.273438 0.781250 +v 0.132812 -0.226562 0.796875 +v -0.132812 -0.226562 0.796875 +v 0.109375 -0.132812 0.781250 +v -0.109375 -0.132812 0.781250 +v 0.039062 -0.125000 0.781250 +v -0.039062 -0.125000 0.781250 +v 0.000000 -0.203125 0.828125 +v 0.046875 -0.148438 0.812500 +v -0.046875 -0.148438 0.812500 +v 0.093750 -0.156250 0.812500 +v -0.093750 -0.156250 0.812500 +v 0.109375 -0.226562 0.828125 +v -0.109375 -0.226562 0.828125 +v 0.078125 -0.250000 0.804688 +v -0.078125 -0.250000 0.804688 +v 0.000000 -0.289062 0.804688 +v 0.257812 -0.312500 0.554688 +v -0.257812 -0.312500 0.554688 +v 0.164062 -0.242188 0.710938 +v -0.164062 -0.242188 0.710938 +v 0.179688 -0.312500 0.710938 +v -0.179688 -0.312500 0.710938 +v 0.234375 -0.250000 0.554688 +v -0.234375 -0.250000 0.554688 +v 0.000000 -0.875000 0.687500 +v 0.046875 -0.867188 0.687500 +v -0.046875 -0.867188 0.687500 +v 0.093750 -0.820312 0.710938 +v -0.093750 -0.820312 0.710938 +v 0.093750 -0.742188 0.726562 +v -0.093750 -0.742188 0.726562 +v 0.000000 -0.781250 0.656250 +v 0.093750 -0.750000 0.664062 +v -0.093750 -0.750000 0.664062 +v 0.093750 -0.812500 0.640625 +v -0.093750 -0.812500 0.640625 +v 0.046875 -0.851562 0.632812 +v -0.046875 -0.851562 0.632812 +v 0.000000 -0.859375 0.632812 +v 0.171875 0.218750 0.781250 +v -0.171875 0.218750 0.781250 +v 0.187500 0.156250 0.773438 +v -0.187500 0.156250 0.773438 +v 0.335938 0.429688 0.757812 +v -0.335938 0.429688 0.757812 +v 0.273438 0.421875 0.773438 +v -0.273438 0.421875 0.773438 +v 0.421875 0.398438 0.773438 +v -0.421875 0.398438 0.773438 +v 0.562500 0.351562 0.695312 +v -0.562500 0.351562 0.695312 +v 0.585938 0.289062 0.687500 +v -0.585938 0.289062 0.687500 +v 0.578125 0.195312 0.679688 +v -0.578125 0.195312 0.679688 +v 0.476562 0.101562 0.718750 +v -0.476562 0.101562 0.718750 +v 0.375000 0.062500 0.742188 +v -0.375000 0.062500 0.742188 +v 0.226562 0.109375 0.781250 +v -0.226562 0.109375 0.781250 +v 0.179688 0.296875 0.781250 +v -0.179688 0.296875 0.781250 +v 0.210938 0.375000 0.781250 +v -0.210938 0.375000 0.781250 +v 0.234375 0.359375 0.757812 +v -0.234375 0.359375 0.757812 +v 0.195312 0.296875 0.757812 +v -0.195312 0.296875 0.757812 +v 0.242188 0.125000 0.757812 +v -0.242188 0.125000 0.757812 +v 0.375000 0.085938 0.726562 +v -0.375000 0.085938 0.726562 +v 0.460938 0.117188 0.703125 +v -0.460938 0.117188 0.703125 +v 0.546875 0.210938 0.671875 +v -0.546875 0.210938 0.671875 +v 0.554688 0.281250 0.671875 +v -0.554688 0.281250 0.671875 +v 0.531250 0.335938 0.679688 +v -0.531250 0.335938 0.679688 +v 0.414062 0.390625 0.750000 +v -0.414062 0.390625 0.750000 +v 0.281250 0.398438 0.765625 +v -0.281250 0.398438 0.765625 +v 0.335938 0.406250 0.750000 +v -0.335938 0.406250 0.750000 +v 0.203125 0.171875 0.750000 +v -0.203125 0.171875 0.750000 +v 0.195312 0.226562 0.750000 +v -0.195312 0.226562 0.750000 +v 0.109375 0.460938 0.609375 +v -0.109375 0.460938 0.609375 +v 0.195312 0.664062 0.617188 +v -0.195312 0.664062 0.617188 +v 0.335938 0.687500 0.593750 +v -0.335938 0.687500 0.593750 +v 0.484375 0.554688 0.554688 +v -0.484375 0.554688 0.554688 +v 0.679688 0.453125 0.492188 +v -0.679688 0.453125 0.492188 +v 0.796875 0.406250 0.460938 +v -0.796875 0.406250 0.460938 +v 0.773438 0.164062 0.375000 +v -0.773438 0.164062 0.375000 +v 0.601562 0.000000 0.414062 +v -0.601562 0.000000 0.414062 +v 0.437500 -0.093750 0.468750 +v -0.437500 -0.093750 0.468750 +v 0.000000 0.898438 0.289062 +v 0.000000 0.984375 -0.078125 +v 0.000000 -0.195312 -0.671875 +v 0.000000 -0.460938 0.187500 +v 0.000000 -0.976562 0.460938 +v 0.000000 -0.804688 0.343750 +v 0.000000 -0.570312 0.320312 +v 0.000000 -0.484375 0.281250 +v 0.851562 0.234375 0.054688 +v -0.851562 0.234375 0.054688 +v 0.859375 0.320312 -0.046875 +v -0.859375 0.320312 -0.046875 +v 0.773438 0.265625 -0.437500 +v -0.773438 0.265625 -0.437500 +v 0.460938 0.437500 -0.703125 +v -0.460938 0.437500 -0.703125 +v 0.734375 -0.046875 0.070312 +v -0.734375 -0.046875 0.070312 +v 0.593750 -0.125000 -0.164062 +v -0.593750 -0.125000 -0.164062 +v 0.640625 -0.007812 -0.429688 +v -0.640625 -0.007812 -0.429688 +v 0.335938 0.054688 -0.664062 +v -0.335938 0.054688 -0.664062 +v 0.234375 -0.351562 0.406250 +v -0.234375 -0.351562 0.406250 +v 0.179688 -0.414062 0.257812 +v -0.179688 -0.414062 0.257812 +v 0.289062 -0.710938 0.382812 +v -0.289062 -0.710938 0.382812 +v 0.250000 -0.500000 0.390625 +v -0.250000 -0.500000 0.390625 +v 0.328125 -0.914062 0.398438 +v -0.328125 -0.914062 0.398438 +v 0.140625 -0.757812 0.367188 +v -0.140625 -0.757812 0.367188 +v 0.125000 -0.539062 0.359375 +v -0.125000 -0.539062 0.359375 +v 0.164062 -0.945312 0.437500 +v -0.164062 -0.945312 0.437500 +v 0.218750 -0.281250 0.429688 +v -0.218750 -0.281250 0.429688 +v 0.210938 -0.226562 0.468750 +v -0.210938 -0.226562 0.468750 +v 0.203125 -0.171875 0.500000 +v -0.203125 -0.171875 0.500000 +v 0.210938 -0.390625 0.164062 +v -0.210938 -0.390625 0.164062 +v 0.296875 -0.312500 -0.265625 +v -0.296875 -0.312500 -0.265625 +v 0.343750 -0.148438 -0.539062 +v -0.343750 -0.148438 -0.539062 +v 0.453125 0.867188 -0.382812 +v -0.453125 0.867188 -0.382812 +v 0.453125 0.929688 -0.070312 +v -0.453125 0.929688 -0.070312 +v 0.453125 0.851562 0.234375 +v -0.453125 0.851562 0.234375 +v 0.460938 0.523438 0.429688 +v -0.460938 0.523438 0.429688 +v 0.726562 0.406250 0.335938 +v -0.726562 0.406250 0.335938 +v 0.632812 0.453125 0.281250 +v -0.632812 0.453125 0.281250 +v 0.640625 0.703125 0.054688 +v -0.640625 0.703125 0.054688 +v 0.796875 0.562500 0.125000 +v -0.796875 0.562500 0.125000 +v 0.796875 0.617188 -0.117188 +v -0.796875 0.617188 -0.117188 +v 0.640625 0.750000 -0.195312 +v -0.640625 0.750000 -0.195312 +v 0.640625 0.679688 -0.445312 +v -0.640625 0.679688 -0.445312 +v 0.796875 0.539062 -0.359375 +v -0.796875 0.539062 -0.359375 +v 0.617188 0.328125 -0.585938 +v -0.617188 0.328125 -0.585938 +v 0.484375 0.023438 -0.546875 +v -0.484375 0.023438 -0.546875 +v 0.820312 0.328125 -0.203125 +v -0.820312 0.328125 -0.203125 +v 0.406250 -0.171875 0.148438 +v -0.406250 -0.171875 0.148438 +v 0.429688 -0.195312 -0.210938 +v -0.429688 -0.195312 -0.210938 +v 0.890625 0.406250 -0.234375 +v -0.890625 0.406250 -0.234375 +v 0.773438 -0.140625 -0.125000 +v -0.773438 -0.140625 -0.125000 +v 1.039062 -0.101562 -0.328125 +v -1.039062 -0.101562 -0.328125 +v 1.281250 0.054688 -0.429688 +v -1.281250 0.054688 -0.429688 +v 1.351562 0.320312 -0.421875 +v -1.351562 0.320312 -0.421875 +v 1.234375 0.507812 -0.421875 +v -1.234375 0.507812 -0.421875 +v 1.023438 0.476562 -0.312500 +v -1.023438 0.476562 -0.312500 +v 1.015625 0.414062 -0.289062 +v -1.015625 0.414062 -0.289062 +v 1.187500 0.437500 -0.390625 +v -1.187500 0.437500 -0.390625 +v 1.265625 0.289062 -0.406250 +v -1.265625 0.289062 -0.406250 +v 1.210938 0.078125 -0.406250 +v -1.210938 0.078125 -0.406250 +v 1.031250 -0.039062 -0.304688 +v -1.031250 -0.039062 -0.304688 +v 0.828125 -0.070312 -0.132812 +v -0.828125 -0.070312 -0.132812 +v 0.921875 0.359375 -0.218750 +v -0.921875 0.359375 -0.218750 +v 0.945312 0.304688 -0.289062 +v -0.945312 0.304688 -0.289062 +v 0.882812 -0.023438 -0.210938 +v -0.882812 -0.023438 -0.210938 +v 1.039062 0.000000 -0.367188 +v -1.039062 0.000000 -0.367188 +v 1.187500 0.093750 -0.445312 +v -1.187500 0.093750 -0.445312 +v 1.234375 0.250000 -0.445312 +v -1.234375 0.250000 -0.445312 +v 1.171875 0.359375 -0.437500 +v -1.171875 0.359375 -0.437500 +v 1.023438 0.343750 -0.359375 +v -1.023438 0.343750 -0.359375 +v 0.843750 0.289062 -0.210938 +v -0.843750 0.289062 -0.210938 +v 0.835938 0.171875 -0.273438 +v -0.835938 0.171875 -0.273438 +v 0.757812 0.093750 -0.273438 +v -0.757812 0.093750 -0.273438 +v 0.820312 0.085938 -0.273438 +v -0.820312 0.085938 -0.273438 +v 0.843750 0.015625 -0.273438 +v -0.843750 0.015625 -0.273438 +v 0.812500 -0.015625 -0.273438 +v -0.812500 -0.015625 -0.273438 +v 0.726562 0.000000 -0.070312 +v -0.726562 0.000000 -0.070312 +v 0.718750 -0.023438 -0.171875 +v -0.718750 -0.023438 -0.171875 +v 0.718750 0.039062 -0.187500 +v -0.718750 0.039062 -0.187500 +v 0.796875 0.203125 -0.210938 +v -0.796875 0.203125 -0.210938 +v 0.890625 0.242188 -0.265625 +v -0.890625 0.242188 -0.265625 +v 0.890625 0.234375 -0.320312 +v -0.890625 0.234375 -0.320312 +v 0.812500 -0.015625 -0.320312 +v -0.812500 -0.015625 -0.320312 +v 0.851562 0.015625 -0.320312 +v -0.851562 0.015625 -0.320312 +v 0.828125 0.078125 -0.320312 +v -0.828125 0.078125 -0.320312 +v 0.765625 0.093750 -0.320312 +v -0.765625 0.093750 -0.320312 +v 0.843750 0.171875 -0.320312 +v -0.843750 0.171875 -0.320312 +v 1.039062 0.328125 -0.414062 +v -1.039062 0.328125 -0.414062 +v 1.187500 0.343750 -0.484375 +v -1.187500 0.343750 -0.484375 +v 1.257812 0.242188 -0.492188 +v -1.257812 0.242188 -0.492188 +v 1.210938 0.085938 -0.484375 +v -1.210938 0.085938 -0.484375 +v 1.046875 0.000000 -0.421875 +v -1.046875 0.000000 -0.421875 +v 0.882812 -0.015625 -0.265625 +v -0.882812 -0.015625 -0.265625 +v 0.953125 0.289062 -0.343750 +v -0.953125 0.289062 -0.343750 +v 0.890625 0.109375 -0.328125 +v -0.890625 0.109375 -0.328125 +v 0.937500 0.062500 -0.335938 +v -0.937500 0.062500 -0.335938 +v 1.000000 0.125000 -0.367188 +v -1.000000 0.125000 -0.367188 +v 0.960938 0.171875 -0.351562 +v -0.960938 0.171875 -0.351562 +v 1.015625 0.234375 -0.375000 +v -1.015625 0.234375 -0.375000 +v 1.054688 0.187500 -0.382812 +v -1.054688 0.187500 -0.382812 +v 1.109375 0.210938 -0.390625 +v -1.109375 0.210938 -0.390625 +v 1.085938 0.273438 -0.390625 +v -1.085938 0.273438 -0.390625 +v 1.023438 0.437500 -0.484375 +v -1.023438 0.437500 -0.484375 +v 1.250000 0.468750 -0.546875 +v -1.250000 0.468750 -0.546875 +v 1.367188 0.296875 -0.500000 +v -1.367188 0.296875 -0.500000 +v 1.312500 0.054688 -0.531250 +v -1.312500 0.054688 -0.531250 +v 1.039062 -0.085938 -0.492188 +v -1.039062 -0.085938 -0.492188 +v 0.789062 -0.125000 -0.328125 +v -0.789062 -0.125000 -0.328125 +v 0.859375 0.382812 -0.382812 +v -0.859375 0.382812 -0.382812 +vn 0.6650 -0.2008 0.7194 +vn -0.6650 -0.2008 0.7194 +vn 0.8294 -0.3036 0.4689 +vn -0.8294 -0.3036 0.4689 +vn 0.4155 -0.7933 0.4449 +vn -0.4155 -0.7933 0.4449 +vn 0.3600 -0.5089 0.7820 +vn -0.3600 -0.5089 0.7820 +vn -0.0787 -0.5394 0.8384 +vn 0.0787 -0.5394 0.8384 +vn -0.2696 -0.8413 0.4685 +vn 0.2696 -0.8413 0.4685 +vn -0.7707 -0.3352 0.5420 +vn 0.7707 -0.3352 0.5420 +vn -0.4689 -0.1940 0.8617 +vn 0.4689 -0.1940 0.8617 +vn -0.4767 0.1907 0.8581 +vn 0.4767 0.1907 0.8581 +vn -0.7672 0.3264 0.5521 +vn 0.7672 0.3264 0.5521 +vn -0.2519 0.8173 0.5182 +vn 0.2519 0.8173 0.5182 +vn -0.0949 0.5696 0.8164 +vn 0.0949 0.5696 0.8164 +vn 0.3667 0.5370 0.7597 +vn -0.3667 0.5370 0.7597 +vn 0.4141 0.7672 0.4898 +vn -0.4141 0.7672 0.4898 +vn 0.8277 0.2952 0.4771 +vn -0.8277 0.2952 0.4771 +vn 0.6713 0.1971 0.7145 +vn -0.6713 0.1971 0.7145 +vn 0.8111 0.3244 -0.4867 +vn -0.8111 0.3244 -0.4867 +vn 0.2052 0.8206 -0.5334 +vn -0.2052 0.8206 -0.5334 +vn -0.4223 0.7806 -0.4607 +vn 0.4223 0.7806 -0.4607 +vn -0.8241 0.3225 -0.4658 +vn 0.8241 0.3225 -0.4658 +vn -0.8137 -0.3487 -0.4650 +vn 0.8137 -0.3487 -0.4650 +vn -0.4223 -0.7806 -0.4607 +vn 0.4223 -0.7806 -0.4607 +vn 0.2052 -0.8206 -0.5334 +vn -0.2052 -0.8206 -0.5334 +vn 0.7995 -0.3510 -0.4875 +vn -0.7995 -0.3510 -0.4875 +vn 0.4000 -0.0623 0.9144 +vn -0.4000 -0.0623 0.9144 +vn 0.3069 -0.1754 0.9354 +vn -0.3069 -0.1754 0.9354 +vn 0.0945 -0.1835 0.9785 +vn -0.0945 -0.1835 0.9785 +vn -0.0624 -0.0283 0.9977 +vn 0.0624 -0.0283 0.9977 +vn -0.0624 0.0260 0.9977 +vn 0.0624 0.0260 0.9977 +vn 0.0996 0.1729 0.9799 +vn -0.0996 0.1729 0.9799 +vn 0.3036 0.1656 0.9383 +vn -0.3036 0.1656 0.9383 +vn 0.4002 0.0572 0.9147 +vn -0.4002 0.0572 0.9147 +vn 0.1231 -0.8616 0.4924 +vn -0.1231 -0.8616 0.4924 +vn 0.2190 -0.8647 0.4520 +vn -0.2190 -0.8647 0.4520 +vn 0.5902 -0.4550 0.6668 +vn -0.5902 -0.4550 0.6668 +vn 0.7689 -0.0506 0.6374 +vn -0.7689 -0.0506 0.6374 +vn 0.7796 0.0900 0.6197 +vn -0.7796 0.0900 0.6197 +vn 0.3241 -0.8188 0.4739 +vn -0.3241 -0.8188 0.4739 +vn 0.3857 -0.6629 0.6417 +vn -0.3857 -0.6629 0.6417 +vn 0.6895 -0.4193 0.5906 +vn -0.6895 -0.4193 0.5906 +vn 0.6588 -0.3634 0.6588 +vn -0.6588 -0.3634 0.6588 +vn 0.5465 0.3707 0.7509 +vn -0.5465 0.3707 0.7509 +vn 0.5064 0.6464 0.5706 +vn -0.5064 0.6464 0.5706 +vn 0.6092 0.5167 0.6015 +vn -0.6092 0.5167 0.6015 +vn -0.0441 0.6610 0.7491 +vn 0.0441 0.6610 0.7491 +vn -0.7246 0.3187 0.6110 +vn 0.7246 0.3187 0.6110 +vn -0.5880 0.5554 0.5880 +vn 0.5880 0.5554 0.5880 +vn 0.5361 -0.3909 0.7482 +vn -0.5361 -0.3909 0.7482 +vn 0.2207 -0.4690 0.8552 +vn -0.2207 -0.4690 0.8552 +vn -0.0794 -0.5321 0.8429 +vn 0.0794 -0.5321 0.8429 +vn -0.0825 -0.6575 0.7490 +vn 0.0825 -0.6575 0.7490 +vn 0.0457 -0.5667 0.8226 +vn -0.0457 -0.5667 0.8226 +vn 0.2784 -0.2130 0.9365 +vn -0.2784 -0.2130 0.9365 +vn 0.3813 -0.1824 0.9063 +vn -0.3813 -0.1824 0.9063 +vn 0.3357 -0.2878 0.8969 +vn -0.3357 -0.2878 0.8969 +vn 0.3762 0.0603 0.9246 +vn -0.3762 0.0603 0.9246 +vn -0.1352 0.2680 0.9539 +vn 0.1352 0.2680 0.9539 +vn 0.3961 -0.4321 0.8102 +vn -0.3961 -0.4321 0.8102 +vn 0.1856 -0.2474 0.9510 +vn -0.1856 -0.2474 0.9510 +vn 0.0099 -0.1948 0.9808 +vn -0.0099 -0.1948 0.9808 +vn 0.0721 -0.6966 0.7138 +vn -0.0721 -0.6966 0.7138 +vn 0.1863 -0.5723 0.7986 +vn -0.1863 -0.5723 0.7986 +vn 0.3157 -0.2708 0.9094 +vn -0.3157 -0.2708 0.9094 +vn 0.3063 -0.0265 0.9516 +vn -0.3063 -0.0265 0.9516 +vn 0.3266 -0.1306 0.9361 +vn -0.3266 -0.1306 0.9361 +vn -0.0137 0.0574 0.9983 +vn 0.0137 0.0574 0.9983 +vn -0.0026 -0.0656 0.9978 +vn 0.0026 -0.0656 0.9978 +vn -0.0000 -0.0000 1.0000 +vn 0.8174 -0.5744 -0.0442 +vn -0.8174 -0.5744 -0.0442 +vn 0.9494 0.2297 -0.2144 +vn -0.9494 0.2297 -0.2144 +vn 0.0825 0.9073 -0.4124 +vn -0.0825 0.9073 -0.4124 +vn -0.8836 0.3555 0.3047 +vn 0.8836 0.3555 0.3047 +vn 0.4207 -0.8797 0.2218 +vn -0.4207 -0.8797 0.2218 +vn 0.2873 -0.5747 0.7663 +vn -0.2873 -0.5747 0.7663 +vn -0.6542 0.6019 0.4580 +vn 0.6542 0.6019 0.4580 +vn 0.1052 0.7892 0.6051 +vn -0.1052 0.7892 0.6051 +vn 0.7582 0.2916 0.5832 +vn -0.7582 0.2916 0.5832 +vn 0.3889 -0.7130 0.5834 +vn -0.3889 -0.7130 0.5834 +vn 0.0463 0.2314 0.9718 +vn -0.0463 0.2314 0.9718 +vn 0.0335 -0.4018 0.9151 +vn -0.0335 -0.4018 0.9151 +vn -0.4452 -0.1610 0.8809 +vn 0.4452 -0.1610 0.8809 +vn -0.2182 -0.4364 0.8729 +vn 0.2182 -0.4364 0.8729 +vn 0.4341 -0.1290 0.8916 +vn -0.4341 -0.1290 0.8916 +vn 0.3008 0.0501 0.9524 +vn -0.3008 0.0501 0.9524 +vn 0.8123 0.3010 0.4996 +vn -0.8123 0.3010 0.4996 +vn 0.8753 0.2574 0.4093 +vn -0.8753 0.2574 0.4093 +vn 0.9385 0.1601 0.3060 +vn -0.9385 0.1601 0.3060 +vn 0.2237 -0.6539 0.7227 +vn -0.2237 -0.6539 0.7227 +vn -0.1536 -0.1997 0.9677 +vn 0.1536 -0.1997 0.9677 +vn -0.2733 -0.1025 0.9565 +vn 0.2733 -0.1025 0.9565 +vn -0.0976 0.1952 0.9759 +vn 0.0976 0.1952 0.9759 +vn -0.1582 0.9494 0.2713 +vn 0.1582 0.9494 0.2713 +vn -0.6934 0.7082 0.1328 +vn 0.6934 0.7082 0.1328 +vn -1.0000 -0.0000 -0.0000 +vn 1.0000 -0.0000 -0.0000 +vn 0.3051 -0.9450 0.1181 +vn -0.3051 -0.9450 0.1181 +vn 0.0298 -0.2981 0.9541 +vn -0.0298 -0.2981 0.9541 +vn 0.1353 -0.3479 0.9277 +vn -0.1353 -0.3479 0.9277 +vn -0.5085 -0.2755 0.8158 +vn 0.5085 -0.2755 0.8158 +vn -0.3843 -0.0419 0.9223 +vn 0.3843 -0.0419 0.9223 +vn -0.2083 0.0374 0.9774 +vn 0.2083 0.0374 0.9774 +vn -0.5721 -0.4767 0.6674 +vn 0.5721 -0.4767 0.6674 +vn -0.1369 -0.7531 0.6435 +vn 0.1369 -0.7531 0.6435 +vn 0.4088 -0.6071 0.6814 +vn -0.4088 -0.6071 0.6814 +vn 0.5740 -0.4130 0.7070 +vn -0.5740 -0.4130 0.7070 +vn 0.5665 -0.0968 0.8183 +vn -0.5665 -0.0968 0.8183 +vn 0.5703 0.1180 0.8129 +vn -0.5703 0.1180 0.8129 +vn 0.4823 0.5621 0.6719 +vn -0.4823 0.5621 0.6719 +vn 0.2604 0.6114 0.7473 +vn -0.2604 0.6114 0.7473 +vn 0.1640 0.3607 0.9182 +vn -0.1640 0.3607 0.9182 +vn -0.0178 0.2495 0.9682 +vn 0.0178 0.2495 0.9682 +vn 0.3273 -0.4166 0.8481 +vn -0.3273 -0.4166 0.8481 +vn 0.2811 -0.2610 0.9235 +vn -0.2811 -0.2610 0.9235 +vn -0.2542 -0.6514 0.7149 +vn 0.2542 -0.6514 0.7149 +vn -0.0260 -0.8455 0.5333 +vn 0.0260 -0.8455 0.5333 +vn -0.3518 -0.2606 0.8991 +vn 0.3518 -0.2606 0.8991 +vn -0.3523 -0.0110 0.9358 +vn 0.3523 -0.0110 0.9358 +vn -0.1317 0.4608 0.8777 +vn 0.1317 0.4608 0.8777 +vn -0.0342 0.6159 0.7870 +vn 0.0342 0.6159 0.7870 +vn 0.3603 0.5836 0.7277 +vn -0.3603 0.5836 0.7277 +vn 0.4988 0.5300 0.6858 +vn -0.4988 0.5300 0.6858 +vn 0.6667 -0.3333 0.6667 +vn -0.6667 -0.3333 0.6667 +vn 0.8165 -0.0731 0.5727 +vn -0.8165 -0.0731 0.5727 +vn 0.7840 0.1161 0.6098 +vn -0.7840 0.1161 0.6098 +vn -0.5306 0.8111 -0.2461 +vn 0.5306 0.8111 -0.2461 +vn -0.8511 0.3695 -0.3730 +vn 0.8511 0.3695 -0.3730 +vn -0.2446 0.8675 -0.4331 +vn 0.2446 0.8675 -0.4331 +vn 0.5924 0.7465 -0.3030 +vn -0.5924 0.7465 -0.3030 +vn 0.3685 0.8758 -0.3118 +vn -0.3685 0.8758 -0.3118 +vn 0.2821 0.9151 -0.2880 +vn -0.2821 0.9151 -0.2880 +vn 0.8561 0.1340 -0.4991 +vn -0.8561 0.1340 -0.4991 +vn 0.5342 -0.7233 -0.4376 +vn -0.5342 -0.7233 -0.4376 +vn 0.3849 -0.8131 -0.4368 +vn -0.3849 -0.8131 -0.4368 +vn 0.2335 -0.5806 -0.7800 +vn -0.2335 -0.5806 -0.7800 +vn 0.2449 -0.0583 -0.9678 +vn -0.2449 -0.0583 -0.9678 +vn 0.1163 -0.4535 -0.8837 +vn -0.1163 -0.4535 -0.8837 +vn 0.1152 -0.9836 -0.1388 +vn -0.1152 -0.9836 -0.1388 +vn 0.1184 -0.9669 -0.2260 +vn -0.1184 -0.9669 -0.2260 +vn 0.9597 -0.0085 -0.2808 +vn -0.9597 -0.0085 -0.2808 +vn 0.9319 0.1629 -0.3242 +vn -0.9319 0.1629 -0.3242 +vn 0.1626 0.0207 -0.9865 +vn -0.1626 0.0207 -0.9865 +vn -0.0188 -0.2177 -0.9758 +vn 0.0188 -0.2177 -0.9758 +vn 0.7538 -0.2926 -0.5884 +vn -0.7538 -0.2926 -0.5884 +vn 0.9196 0.1379 -0.3678 +vn -0.9196 0.1379 -0.3678 +vn 0.9297 0.3127 -0.1944 +vn -0.9297 0.3127 -0.1944 +vn 0.9120 0.3376 -0.2329 +vn -0.9120 0.3376 -0.2329 +vn 0.9407 0.3338 -0.0607 +vn -0.9407 0.3338 -0.0607 +vn 0.1761 -0.8805 -0.4402 +vn -0.1761 -0.8805 -0.4402 +vn 0.3708 -0.4733 -0.7991 +vn -0.3708 -0.4733 -0.7991 +vn 0.3107 -0.8284 -0.4660 +vn -0.3107 -0.8284 -0.4660 +vn 0.2793 -0.9515 -0.1287 +vn -0.2793 -0.9515 -0.1287 +vn 0.3139 -0.9321 -0.1807 +vn -0.3139 -0.9321 -0.1807 +vn 0.9762 -0.2083 -0.0609 +vn -0.9762 -0.2083 -0.0609 +vn 0.8267 -0.5066 0.2447 +vn -0.8267 -0.5066 0.2447 +vn 0.3449 -0.1158 -0.9315 +vn -0.3449 -0.1158 -0.9315 +vn 0.1203 0.9644 0.2355 +vn -0.1203 0.9644 0.2355 +vn 0.1275 0.9744 -0.1851 +vn -0.1275 0.9744 -0.1851 +vn 0.3492 0.5947 -0.7241 +vn -0.3492 0.5947 -0.7241 +vn 0.4153 0.8981 -0.1449 +vn -0.4153 0.8981 -0.1449 +vn 0.1845 0.7036 0.6863 +vn -0.1845 0.7036 0.6863 +vn 0.6056 0.7794 0.1608 +vn -0.6056 0.7794 0.1608 +vn 0.7033 0.6806 -0.2053 +vn -0.7033 0.6806 -0.2053 +vn 0.6679 0.2007 -0.7166 +vn -0.6679 0.2007 -0.7166 +vn 0.4948 0.4342 -0.7528 +vn -0.4948 0.4342 -0.7528 +vn 0.6423 0.7459 -0.1761 +vn -0.6423 0.7459 -0.1761 +vn 0.7182 0.6788 0.1530 +vn -0.7182 0.6788 0.1530 +vn 0.7388 0.3972 0.5444 +vn -0.7388 0.3972 0.5444 +vn 0.3428 0.9261 -0.1579 +vn -0.3428 0.9261 -0.1579 +vn 0.2270 0.5740 0.7867 +vn -0.2270 0.5740 0.7867 +vn -0.1722 0.1046 -0.9795 +vn 0.1722 0.1046 -0.9795 +vn 0.0425 0.9150 0.4013 +vn -0.0425 0.9150 0.4013 +vn -0.1616 0.1847 0.9694 +vn 0.1616 0.1847 0.9694 +vn 0.9791 0.1973 0.0483 +vn -0.9791 0.1973 0.0483 +vn 0.9470 0.0918 0.3079 +vn -0.9470 0.0918 0.3079 +vn 0.9794 0.1905 -0.0661 +vn -0.9794 0.1905 -0.0661 +vn 0.9938 0.0312 -0.1070 +vn -0.9938 0.0312 -0.1070 +vn 0.7116 -0.7008 0.0501 +vn -0.7116 -0.7008 0.0501 +vn 0.3722 -0.9243 0.0847 +vn -0.3722 -0.9243 0.0847 +vn 0.4465 -0.8644 0.2310 +vn -0.4465 -0.8644 0.2310 +vn 0.6066 -0.7578 0.2405 +vn -0.6066 -0.7578 0.2405 +vn 0.7325 -0.6368 0.2407 +vn -0.7325 -0.6368 0.2407 +vn 0.2637 -0.4499 0.8533 +vn -0.2637 -0.4499 0.8533 +vn 0.5568 -0.3181 -0.7673 +vn -0.5568 -0.3181 -0.7673 +vn 0.5004 -0.2807 -0.8190 +vn -0.5004 -0.2807 -0.8190 +vn 0.3190 -0.8494 -0.4205 +vn -0.3190 -0.8494 -0.4205 +vn 0.7198 -0.6356 -0.2793 +vn -0.7198 -0.6356 -0.2793 +vn 0.4972 -0.4408 -0.7473 +vn -0.4972 -0.4408 -0.7473 +vn 0.3506 0.3807 0.8557 +vn -0.3506 0.3807 0.8557 +vn 0.4566 0.1715 0.8730 +vn -0.4566 0.1715 0.8730 +vn 0.2583 0.1055 0.9603 +vn -0.2583 0.1055 0.9603 +vn 0.2455 -0.0802 0.9661 +vn -0.2455 -0.0802 0.9661 +vn 0.4643 -0.0599 0.8837 +vn -0.4643 -0.0599 0.8837 +vn 0.6225 -0.3045 0.7210 +vn -0.6225 -0.3045 0.7210 +vn 0.4500 0.6590 0.6027 +vn -0.4500 0.6590 0.6027 +vn -0.2667 0.8309 0.4884 +vn 0.2667 0.8309 0.4884 +vn -0.8284 0.2291 0.5111 +vn 0.8284 0.2291 0.5111 +vn -0.5251 -0.3566 0.7727 +vn 0.5251 -0.3566 0.7727 +vn 0.4546 -0.5665 0.6873 +vn -0.4546 -0.5665 0.6873 +vn 0.6996 -0.4497 0.5552 +vn -0.6996 -0.4497 0.5552 +vn 0.7220 -0.6827 -0.1126 +vn -0.7220 -0.6827 -0.1126 +vn -0.1919 0.2860 0.9388 +vn 0.1919 0.2860 0.9388 +vn 0.9048 -0.3734 -0.2047 +vn -0.9048 -0.3734 -0.2047 +vn 0.1034 0.1551 0.9825 +vn -0.1034 0.1551 0.9825 +vn 0.0841 0.9318 0.3530 +vn -0.0841 0.9318 0.3530 +vn 0.6446 -0.0883 0.7594 +vn -0.6446 -0.0883 0.7594 +vn 0.4309 0.4740 0.7678 +vn -0.4309 0.4740 0.7678 +vn 0.8032 -0.4847 0.3462 +vn -0.8032 -0.4847 0.3462 +vn 0.5811 -0.4128 0.7014 +vn -0.5811 -0.4128 0.7014 +vn 0.5910 -0.4305 0.6822 +vn -0.5910 -0.4305 0.6822 +vn 0.9818 -0.1804 -0.0591 +vn -0.9818 -0.1804 -0.0591 +vn 0.9105 -0.3965 -0.1175 +vn -0.9105 -0.3965 -0.1175 +vn 0.9972 -0.0181 -0.0725 +vn -0.9972 -0.0181 -0.0725 +vn 0.7313 -0.6543 0.1925 +vn -0.7313 -0.6543 0.1925 +vn 0.7867 -0.6079 0.1073 +vn -0.7867 -0.6079 0.1073 +vn 0.7022 -0.7022 0.1170 +vn -0.7022 -0.7022 0.1170 +vn 0.1840 0.9816 -0.0511 +vn -0.1840 0.9816 -0.0511 +vn 0.9352 0.3301 0.1284 +vn -0.9352 0.3301 0.1284 +vn 0.6633 -0.7463 0.0553 +vn -0.6633 -0.7463 0.0553 +vn -0.0085 0.9970 0.0767 +vn 0.0085 0.9970 0.0767 +vn 0.6237 -0.7061 0.3354 +vn -0.6237 -0.7061 0.3354 +vn 0.2733 -0.8925 0.3587 +vn -0.2733 -0.8925 0.3587 +vn -0.8328 -0.5080 -0.2200 +vn 0.8328 -0.5080 -0.2200 +vn -0.8339 0.2377 -0.4981 +vn 0.8339 0.2377 -0.4981 +vn -0.5655 0.7847 -0.2539 +vn 0.5655 0.7847 -0.2539 +vn -0.0560 0.9962 0.0672 +vn 0.0560 0.9962 0.0672 +vn 0.1445 0.0222 0.9893 +vn -0.1445 0.0222 0.9893 +vn 0.3275 0.0645 0.9427 +vn -0.3275 0.0645 0.9427 +vn 0.3127 0.0232 0.9496 +vn -0.3127 0.0232 0.9496 +vn 0.1710 0.0274 0.9849 +vn -0.1710 0.0274 0.9849 +vn 0.3487 0.2849 0.8929 +vn -0.3487 0.2849 0.8929 +vn 0.4006 -0.0343 0.9156 +vn -0.4006 -0.0343 0.9156 +vn 0.2572 -0.0603 0.9645 +vn -0.2572 -0.0603 0.9645 +vn 0.0637 -0.0106 0.9979 +vn -0.0637 -0.0106 0.9979 +vn -0.3637 0.7039 0.6101 +vn 0.3637 0.7039 0.6101 +vn 0.6299 0.0355 0.7759 +vn -0.6299 0.0355 0.7759 +vn 0.4472 -0.2002 0.8717 +vn -0.4472 -0.2002 0.8717 +vn 0.5072 -0.2141 0.8348 +vn -0.5072 -0.2141 0.8348 +vn 0.5258 0.2619 0.8093 +vn -0.5258 0.2619 0.8093 +vn 0.2980 0.5802 0.7580 +vn -0.2980 0.5802 0.7580 +vn 0.0930 -0.9924 -0.0805 +vn -0.0930 -0.9924 -0.0805 +vn 0.5006 -0.8657 0.0080 +vn -0.5006 -0.8657 0.0080 +vn 0.9285 -0.2497 0.2748 +vn -0.9285 -0.2497 0.2748 +vn 0.8393 0.5424 -0.0378 +vn -0.8393 0.5424 -0.0378 +vn -0.2355 0.9367 -0.2589 +vn 0.2355 0.9367 -0.2589 +vn -0.4499 0.8838 -0.1285 +vn 0.4499 0.8838 -0.1285 +vn -0.5384 -0.0098 -0.8427 +vn 0.5384 -0.0098 -0.8427 +vn -0.1910 -0.0241 -0.9813 +vn 0.1910 -0.0241 -0.9813 +vn 0.4046 0.0266 -0.9141 +vn -0.4046 0.0266 -0.9141 +vn -0.7819 0.6231 0.0197 +vn 0.7819 0.6231 0.0197 +vn 0.5428 -0.2063 -0.8142 +vn -0.5428 -0.2063 -0.8142 +vn -0.2474 -0.9231 -0.2945 +vn 0.2474 -0.9231 -0.2945 +vt 0.890955 0.590063 +vt 0.870622 0.589649 +vt 0.860081 0.560115 +vt 0.904571 0.559404 +vt 0.856226 0.850547 +vt 0.868067 0.821510 +vt 0.888398 0.821999 +vt 0.900640 0.853232 +vt 0.853018 0.521562 +vt 0.920166 0.524546 +vt 0.847458 0.888748 +vt 0.914672 0.888748 +vt 0.828900 0.590771 +vt 0.798481 0.569535 +vt 0.795104 0.838402 +vt 0.826436 0.818537 +vt 0.854402 0.604754 +vt 0.852534 0.805700 +vt 0.854107 0.625459 +vt 0.828171 0.633354 +vt 0.827598 0.775964 +vt 0.853157 0.785002 +vt 0.791018 0.645443 +vt 0.791018 0.762238 +vt 0.855181 0.668527 +vt 0.842358 0.702491 +vt 0.844839 0.707525 +vt 0.856142 0.742025 +vt 0.867508 0.642291 +vt 0.867293 0.768782 +vt 0.890474 0.641909 +vt 0.900375 0.666964 +vt 0.901223 0.745592 +vt 0.890219 0.770183 +vt 0.918898 0.699697 +vt 0.921180 0.713713 +vt 0.931889 0.636832 +vt 0.968392 0.645333 +vt 0.968213 0.770220 +vt 0.931368 0.777093 +vt 0.905882 0.627902 +vt 0.904990 0.784860 +vt 0.906232 0.605742 +vt 0.933717 0.593037 +vt 0.931250 0.820926 +vt 0.904357 0.807013 +vt 0.968392 0.573812 +vt 0.965038 0.841671 +vt 0.902359 0.607909 +vt 0.889591 0.593275 +vt 0.900583 0.804677 +vt 0.887178 0.818729 +vt 0.899781 0.626257 +vt 0.898822 0.786233 +vt 0.887842 0.636527 +vt 0.887351 0.775442 +vt 0.870908 0.635245 +vt 0.870376 0.775972 +vt 0.859881 0.623942 +vt 0.858859 0.786774 +vt 0.859664 0.608186 +vt 0.857942 0.802505 +vt 0.871664 0.593961 +vt 0.869299 0.817249 +vt 0.879400 0.616512 +vt 0.878029 0.795063 +vt 0.540260 0.053805 +vt 0.536419 0.062072 +vt 0.518925 0.059681 +vt 0.518916 0.050294 +vt 0.501452 0.062043 +vt 0.497626 0.053770 +vt 0.551930 0.058338 +vt 0.542788 0.064089 +vt 0.495083 0.064047 +vt 0.485955 0.058273 +vt 0.555073 0.061900 +vt 0.546290 0.072669 +vt 0.491565 0.072625 +vt 0.482805 0.061829 +vt 0.563812 0.076586 +vt 0.548333 0.084893 +vt 0.489507 0.084858 +vt 0.474014 0.076511 +vt 0.583135 0.108495 +vt 0.555621 0.121749 +vt 0.482177 0.121781 +vt 0.454527 0.108481 +vt 0.605512 0.165134 +vt 0.647395 0.200502 +vt 0.621513 0.227818 +vt 0.553118 0.209599 +vt 0.416514 0.229490 +vt 0.389677 0.201890 +vt 0.432024 0.165644 +vt 0.485339 0.210053 +vt 0.676379 0.233241 +vt 0.664761 0.253225 +vt 0.372747 0.256357 +vt 0.360308 0.235899 +vt 0.715342 0.265392 +vt 0.683908 0.279995 +vt 0.353696 0.284606 +vt 0.320452 0.270303 +vt 0.707254 0.310054 +vt 0.687515 0.311539 +vt 0.351187 0.317440 +vt 0.330721 0.316853 +vt 0.697446 0.332673 +vt 0.676824 0.323937 +vt 0.362723 0.329722 +vt 0.341964 0.339667 +vt 0.662817 0.372521 +vt 0.639050 0.357330 +vt 0.402772 0.362131 +vt 0.379297 0.378686 +vt 0.626842 0.395792 +vt 0.618316 0.375151 +vt 0.424583 0.379267 +vt 0.416915 0.400552 +vt 0.604826 0.397804 +vt 0.600808 0.377857 +vt 0.442396 0.381222 +vt 0.439252 0.401540 +vt 0.553095 0.390512 +vt 0.559674 0.357011 +vt 0.482938 0.358497 +vt 0.490934 0.391862 +vt 0.521923 0.386009 +vt 0.521086 0.343868 +vt 0.577279 0.340156 +vt 0.599845 0.344815 +vt 0.441977 0.347815 +vt 0.464579 0.342230 +vt 0.615546 0.342005 +vt 0.425972 0.345582 +vt 0.634472 0.332311 +vt 0.406362 0.336480 +vt 0.662406 0.312804 +vt 0.377061 0.317685 +vt 0.668440 0.297958 +vt 0.370304 0.302644 +vt 0.664101 0.277872 +vt 0.374100 0.281778 +vt 0.639236 0.253047 +vt 0.398938 0.255633 +vt 0.613992 0.242662 +vt 0.424464 0.244473 +vt 0.572941 0.258564 +vt 0.466409 0.259709 +vt 0.563905 0.272007 +vt 0.519760 0.248864 +vt 0.475886 0.273078 +vt 0.558527 0.316594 +vt 0.482619 0.317843 +vt 0.520277 0.294764 +vt 0.556923 0.291214 +vt 0.483433 0.292249 +vt 0.525483 0.068967 +vt 0.518928 0.067899 +vt 0.512375 0.068956 +vt 0.531231 0.073829 +vt 0.506626 0.073811 +vt 0.531019 0.087431 +vt 0.506827 0.087416 +vt 0.532042 0.127713 +vt 0.532669 0.090920 +vt 0.505177 0.090908 +vt 0.505828 0.127728 +vt 0.538112 0.158382 +vt 0.518981 0.151749 +vt 0.518941 0.128358 +vt 0.499851 0.158434 +vt 0.518925 0.093952 +vt 0.518927 0.085180 +vt 0.548362 0.173560 +vt 0.537959 0.175966 +vt 0.535214 0.166808 +vt 0.502799 0.166857 +vt 0.500100 0.176033 +vt 0.489683 0.173693 +vt 0.544281 0.193366 +vt 0.537248 0.187577 +vt 0.500890 0.187571 +vt 0.493996 0.193428 +vt 0.519841 0.200843 +vt 0.528757 0.191785 +vt 0.509219 0.191626 +vt 0.517577 0.190607 +vt 0.519132 0.185382 +vt 0.518998 0.159028 +vt 0.531131 0.171631 +vt 0.519016 0.165599 +vt 0.506910 0.171667 +vt 0.519099 0.179457 +vt 0.528222 0.186316 +vt 0.509787 0.186260 +vt 0.533528 0.184215 +vt 0.504547 0.184206 +vt 0.533449 0.176739 +vt 0.504604 0.176791 +vt 0.561572 0.167779 +vt 0.476363 0.167996 +vt 0.559475 0.149319 +vt 0.478371 0.149447 +vt 0.596138 0.133426 +vt 0.441395 0.133592 +vt 0.601169 0.147885 +vt 0.436337 0.148194 +vt 0.518925 0.083865 +vt 0.528933 0.084957 +vt 0.508915 0.084945 +vt 0.529036 0.075429 +vt 0.508820 0.075415 +vt 0.523751 0.070508 +vt 0.514106 0.070501 +vt 0.518929 0.069468 +vt 0.521560 0.074970 +vt 0.518928 0.074259 +vt 0.516297 0.074966 +vt 0.524236 0.076691 +vt 0.513619 0.076684 +vt 0.524601 0.079886 +vt 0.513252 0.079879 +vt 0.518926 0.079331 +vt 0.571787 0.277295 +vt 0.568351 0.292904 +vt 0.468070 0.278617 +vt 0.471978 0.294282 +vt 0.573085 0.311386 +vt 0.467790 0.313081 +vt 0.584855 0.327708 +vt 0.456477 0.329961 +vt 0.580734 0.266620 +vt 0.458737 0.268049 +vt 0.611720 0.255725 +vt 0.427062 0.257728 +vt 0.632494 0.262853 +vt 0.406068 0.265508 +vt 0.653658 0.279971 +vt 0.384904 0.283634 +vt 0.656064 0.297636 +vt 0.383015 0.301864 +vt 0.652752 0.310186 +vt 0.386858 0.314615 +vt 0.629040 0.323864 +vt 0.411556 0.327673 +vt 0.614408 0.331972 +vt 0.426727 0.335361 +vt 0.601033 0.333624 +vt 0.440344 0.336537 +vt 0.590644 0.321516 +vt 0.601799 0.328453 +vt 0.450408 0.323919 +vt 0.439372 0.331331 +vt 0.613335 0.327083 +vt 0.427623 0.330358 +vt 0.626851 0.320513 +vt 0.413648 0.324175 +vt 0.646248 0.306421 +vt 0.393381 0.310510 +vt 0.649541 0.296225 +vt 0.389662 0.300183 +vt 0.647785 0.283486 +vt 0.391040 0.287071 +vt 0.629829 0.267263 +vt 0.408893 0.269959 +vt 0.612641 0.261560 +vt 0.426254 0.263693 +vt 0.585166 0.270991 +vt 0.454369 0.272583 +vt 0.578124 0.281900 +vt 0.461798 0.283441 +vt 0.579548 0.309340 +vt 0.461204 0.311233 +vt 0.577524 0.293776 +vt 0.462754 0.295432 +vt 0.553209 0.433063 +vt 0.523031 0.433628 +vt 0.492809 0.434538 +vt 0.609819 0.431516 +vt 0.435860 0.435740 +vt 0.648174 0.419316 +vt 0.396518 0.425416 +vt 0.692106 0.388274 +vt 0.350292 0.396229 +vt 0.726332 0.341754 +vt 0.312756 0.350588 +vt 0.735879 0.312112 +vt 0.301067 0.320593 +vt 0.729900 0.256393 +vt 0.304876 0.261087 +vt 0.698172 0.216906 +vt 0.337414 0.219179 +vt 0.663103 0.190671 +vt 0.373474 0.191872 +vt 0.626908 0.015608 +vt 0.649444 0.022378 +vt 0.660451 0.076084 +vt 0.621440 0.048089 +vt 0.376796 0.075296 +vt 0.388827 0.021586 +vt 0.411318 0.015131 +vt 0.416419 0.047631 +vt 0.567460 0.000144 +vt 0.577206 0.032801 +vt 0.470636 0.000144 +vt 0.460782 0.032656 +vt 0.518922 0.024886 +vt 0.547413 0.041724 +vt 0.490511 0.041669 +vt 0.558059 0.053871 +vt 0.479842 0.053785 +vt 0.576951 0.057998 +vt 0.460920 0.057845 +vt 0.611687 0.078268 +vt 0.425932 0.077985 +vt 0.626663 0.111357 +vt 0.410618 0.111244 +vt 0.629482 0.130456 +vt 0.623495 0.146796 +vt 0.413741 0.147158 +vt 0.407648 0.130594 +vt 0.619303 0.159841 +vt 0.418035 0.160361 +vt 0.945900 0.079569 +vt 0.886245 0.121777 +vt 0.849114 0.099732 +vt 0.891780 0.036916 +vt 0.183115 0.092127 +vt 0.141314 0.112482 +vt 0.078961 0.060719 +vt 0.142277 0.021467 +vt 0.788458 0.080826 +vt 0.805584 0.010786 +vt 0.246353 0.076510 +vt 0.232648 0.003484 +vt 0.687018 0.077204 +vt 0.672384 0.022201 +vt 0.349875 0.075955 +vt 0.365979 0.020991 +vt 0.760215 0.193244 +vt 0.789046 0.233323 +vt 0.271553 0.193871 +vt 0.241255 0.236977 +vt 0.994525 0.167705 +vt 0.909112 0.183261 +vt 0.107928 0.179083 +vt 0.011829 0.155367 +vt 0.911671 0.402429 +vt 0.862868 0.338556 +vt 0.894128 0.301884 +vt 0.962901 0.344752 +vt 0.123776 0.315519 +vt 0.160557 0.356821 +vt 0.106400 0.432652 +vt 0.043968 0.367038 +vt 0.915360 0.259804 +vt 0.999856 0.254640 +vt 0.098965 0.266968 +vt 0.000144 0.259113 +vt 0.749542 0.334683 +vt 0.766337 0.300809 +vt 0.789162 0.313727 +vt 0.267408 0.310142 +vt 0.288183 0.346496 +vt 0.242992 0.325552 +vt 0.815314 0.276388 +vt 0.846174 0.293397 +vt 0.213065 0.285164 +vt 0.178537 0.304983 +vt 0.845007 0.256352 +vt 0.873517 0.265922 +vt 0.179662 0.263312 +vt 0.147089 0.274284 +vt 0.859075 0.228168 +vt 0.886999 0.233769 +vt 0.162803 0.231720 +vt 0.131514 0.237587 +vt 0.842355 0.195160 +vt 0.875030 0.184705 +vt 0.145224 0.182749 +vt 0.176788 0.196179 +vt 0.794286 0.364062 +vt 0.239776 0.382592 +vt 0.770185 0.379538 +vt 0.268122 0.398737 +vt 0.845499 0.449967 +vt 0.185281 0.484099 +vt 0.815858 0.445381 +vt 0.770572 0.444261 +vt 0.755700 0.418603 +vt 0.287033 0.442912 +vt 0.271364 0.473316 +vt 0.219260 0.477186 +vt 0.819845 0.468071 +vt 0.215894 0.503605 +vt 0.809631 0.233887 +vt 0.219168 0.237388 +vt 0.829287 0.219562 +vt 0.199067 0.222464 +vt 0.786480 0.117591 +vt 0.715482 0.139727 +vt 0.246666 0.114850 +vt 0.319538 0.139409 +vt 0.785486 0.152330 +vt 0.245969 0.151002 +vt 0.837382 0.156361 +vt 0.858171 0.137775 +vt 0.171653 0.132294 +vt 0.196622 0.155241 +vt 0.506166 0.904851 +vt 0.432388 0.894943 +vt 0.438797 0.870229 +vt 0.491058 0.881714 +vt 0.315867 0.868209 +vt 0.321637 0.893225 +vt 0.247207 0.901159 +vt 0.263032 0.878321 +vt 0.572792 0.860484 +vt 0.604825 0.879946 +vt 0.181486 0.854693 +vt 0.148729 0.873349 +vt 0.586396 0.793977 +vt 0.619962 0.791615 +vt 0.169745 0.787474 +vt 0.136063 0.784093 +vt 0.549027 0.746412 +vt 0.563786 0.739211 +vt 0.208656 0.740879 +vt 0.194086 0.733241 +vt 0.500314 0.711729 +vt 0.508270 0.697693 +vt 0.258399 0.707497 +vt 0.250811 0.693249 +vt 0.438641 0.680683 +vt 0.434803 0.658882 +vt 0.320962 0.677959 +vt 0.325318 0.656224 +vt 0.505666 0.730944 +vt 0.452955 0.700023 +vt 0.306136 0.696976 +vt 0.252524 0.726592 +vt 0.542850 0.755753 +vt 0.214575 0.750414 +vt 0.568148 0.787367 +vt 0.188269 0.781375 +vt 0.555495 0.826352 +vt 0.199850 0.820889 +vt 0.501231 0.844356 +vt 0.253846 0.840502 +vt 0.457832 0.840040 +vt 0.297562 0.837358 +vt 0.796021 0.176969 +vt 0.783193 0.187449 +vt 0.233625 0.175620 +vt 0.246955 0.187075 +vt 0.391039 0.611891 +vt 0.394766 0.686125 +vt 0.369913 0.610196 +vt 0.364838 0.684445 +vt 0.391747 0.862097 +vt 0.401605 0.841460 +vt 0.354026 0.840297 +vt 0.363377 0.861308 +vt 0.435018 0.718280 +vt 0.323658 0.715731 +vt 0.433669 0.729661 +vt 0.384658 0.710299 +vt 0.374400 0.708969 +vt 0.324726 0.727177 +vt 0.410995 0.747662 +vt 0.427812 0.742828 +vt 0.347028 0.745816 +vt 0.330270 0.740536 +vt 0.418086 0.784946 +vt 0.384657 0.795423 +vt 0.372270 0.794472 +vt 0.338952 0.783073 +vt 0.431333 0.817535 +vt 0.324790 0.815460 +vt 0.816266 0.203086 +vt 0.825107 0.209762 +vt 0.199767 0.214827 +vt 0.209828 0.206161 +vt 0.802192 0.184609 +vt 0.226485 0.183086 +vt 0.448505 0.804621 +vt 0.473386 0.824700 +vt 0.307886 0.802031 +vt 0.282357 0.821525 +vt 0.435868 0.779569 +vt 0.321237 0.777208 +vt 0.423718 0.754191 +vt 0.334089 0.752045 +vt 0.437950 0.749777 +vt 0.319919 0.747250 +vt 0.445392 0.731997 +vt 0.312907 0.729222 +vt 0.440995 0.724383 +vt 0.317510 0.721697 +vt 0.455277 0.713731 +vt 0.303460 0.710657 +vt 0.512485 0.828811 +vt 0.242975 0.824574 +vt 0.550942 0.811814 +vt 0.204839 0.806417 +vt 0.552139 0.787682 +vt 0.204331 0.782156 +vt 0.539407 0.764539 +vt 0.217774 0.759319 +vt 0.508439 0.743135 +vt 0.249419 0.738732 +vt 0.470841 0.748408 +vt 0.454776 0.761665 +vt 0.286960 0.745020 +vt 0.302729 0.758742 +vt 0.488870 0.770464 +vt 0.475403 0.783904 +vt 0.268291 0.766661 +vt 0.281439 0.780511 +vt 0.503673 0.787562 +vt 0.494476 0.802470 +vt 0.252972 0.783410 +vt 0.261790 0.798626 +vt 0.518562 0.791602 +vt 0.516802 0.807339 +vt 0.237920 0.787045 +vt 0.239243 0.802891 +vt 0.484068 0.628776 +vt 0.543385 0.683538 +vt 0.276936 0.625067 +vt 0.216123 0.678120 +vt 0.581052 0.726933 +vt 0.177176 0.720426 +vt 0.616701 0.759965 +vt 0.140379 0.752377 +vt 0.707492 0.759884 +vt 0.660647 0.741167 +vt 0.049526 0.748824 +vt 0.097038 0.732052 +vt 0.745511 0.652100 +vt 0.677256 0.670436 +vt 0.019409 0.639749 +vt 0.083564 0.662038 +vt 0.740843 0.572428 +vt 0.671403 0.592656 +vt 0.033664 0.564403 +vt 0.092820 0.589862 +vt 0.834578 0.206879 +vt 0.834705 0.206959 +vt 0.051216 0.522659 +vt 0.145041 0.562595 +vt 0.620420 0.565675 +vt 0.498072 0.552315 +vt 0.264218 0.550140 +s 0 +f 47/1/1 1/2/1 3/3/1 45/4/1 +f 4/5/2 2/6/2 48/7/2 46/8/2 +f 45/4/3 3/3/3 5/9/3 43/10/3 +f 6/11/4 4/5/4 46/8/4 44/12/4 +f 3/3/5 9/13/5 7/14/5 5/9/5 +f 8/15/6 10/16/6 4/5/6 6/11/6 +f 1/2/7 11/17/7 9/13/7 3/3/7 +f 10/16/8 12/18/8 2/6/8 4/5/8 +f 11/17/9 13/19/9 15/20/9 9/13/9 +f 16/21/10 14/22/10 12/18/10 10/16/10 +f 9/13/11 15/20/11 17/23/11 7/14/11 +f 18/24/12 16/21/12 10/16/12 8/15/12 +f 15/20/13 21/25/13 19/26/13 17/23/13 +f 20/27/14 22/28/14 16/21/14 18/24/14 +f 13/19/15 23/29/15 21/25/15 15/20/15 +f 22/28/16 24/30/16 14/22/16 16/21/16 +f 23/29/17 25/31/17 27/32/17 21/25/17 +f 28/33/18 26/34/18 24/30/18 22/28/18 +f 21/25/19 27/32/19 29/35/19 19/26/19 +f 30/36/20 28/33/20 22/28/20 20/27/20 +f 27/32/21 33/37/21 31/38/21 29/35/21 +f 32/39/22 34/40/22 28/33/22 30/36/22 +f 25/31/23 35/41/23 33/37/23 27/32/23 +f 34/40/24 36/42/24 26/34/24 28/33/24 +f 35/41/25 37/43/25 39/44/25 33/37/25 +f 40/45/26 38/46/26 36/42/26 34/40/26 +f 33/37/27 39/44/27 41/47/27 31/38/27 +f 42/48/28 40/45/28 34/40/28 32/39/28 +f 39/44/29 45/4/29 43/10/29 41/47/29 +f 44/12/30 46/8/30 40/45/30 42/48/30 +f 37/43/31 47/1/31 45/4/31 39/44/31 +f 46/8/32 48/7/32 38/46/32 40/45/32 +f 47/1/33 37/43/33 51/49/33 49/50/33 +f 52/51/34 38/46/34 48/7/34 50/52/34 +f 37/43/35 35/41/35 53/53/35 51/49/35 +f 54/54/36 36/42/36 38/46/36 52/51/36 +f 35/41/37 25/31/37 55/55/37 53/53/37 +f 56/56/38 26/34/38 36/42/38 54/54/38 +f 25/31/39 23/29/39 57/57/39 55/55/39 +f 58/58/40 24/30/40 26/34/40 56/56/40 +f 23/29/41 13/19/41 59/59/41 57/57/41 +f 60/60/42 14/22/42 24/30/42 58/58/42 +f 13/19/43 11/17/43 63/61/43 59/59/43 +f 64/62/44 12/18/44 14/22/44 60/60/44 +f 11/17/45 1/2/45 65/63/45 63/61/45 +f 66/64/46 2/6/46 12/18/46 64/62/46 +f 1/2/47 47/1/47 49/50/47 65/63/47 +f 50/52/48 48/7/48 2/6/48 66/64/48 +f 61/65/49 65/63/49 49/50/49 +f 50/52/50 66/64/50 62/66/50 +f 63/61/51 65/63/51 61/65/51 +f 62/66/52 66/64/52 64/62/52 +f 61/65/53 59/59/53 63/61/53 +f 64/62/54 60/60/54 62/66/54 +f 61/65/55 57/57/55 59/59/55 +f 60/60/56 58/58/56 62/66/56 +f 61/65/57 55/55/57 57/57/57 +f 58/58/58 56/56/58 62/66/58 +f 61/65/59 53/53/59 55/55/59 +f 56/56/60 54/54/60 62/66/60 +f 61/65/61 51/49/61 53/53/61 +f 54/54/62 52/51/62 62/66/62 +f 61/65/63 49/50/63 51/49/63 +f 52/51/64 50/52/64 62/66/64 +f 89/67/65 174/68/65 176/69/65 91/70/65 +f 176/69/66 175/71/66 90/72/66 91/70/66 +f 87/73/67 172/74/67 174/68/67 89/67/67 +f 175/71/68 173/75/68 88/76/68 90/72/68 +f 85/77/69 170/78/69 172/74/69 87/73/69 +f 173/75/70 171/79/70 86/80/70 88/76/70 +f 83/81/71 168/82/71 170/78/71 85/77/71 +f 171/79/72 169/83/72 84/84/72 86/80/72 +f 81/85/73 166/86/73 168/82/73 83/81/73 +f 169/83/74 167/87/74 82/88/74 84/84/74 +f 79/89/75 92/90/75 146/91/75 164/92/75 +f 147/93/76 93/94/76 80/95/76 165/96/76 +f 92/90/77 94/97/77 148/98/77 146/91/77 +f 149/99/78 95/100/78 93/94/78 147/93/78 +f 94/97/79 96/101/79 150/102/79 148/98/79 +f 151/103/80 97/104/80 95/100/80 149/99/80 +f 96/101/81 98/105/81 152/106/81 150/102/81 +f 153/107/82 99/108/82 97/104/82 151/103/82 +f 98/105/83 100/109/83 154/110/83 152/106/83 +f 155/111/84 101/112/84 99/108/84 153/107/84 +f 100/109/85 102/113/85 156/114/85 154/110/85 +f 157/115/86 103/116/86 101/112/86 155/111/86 +f 102/113/87 104/117/87 158/118/87 156/114/87 +f 159/119/88 105/120/88 103/116/88 157/115/88 +f 104/117/89 106/121/89 160/122/89 158/118/89 +f 161/123/90 107/124/90 105/120/90 159/119/90 +f 106/121/91 108/125/91 162/126/91 160/122/91 +f 163/127/92 109/128/92 107/124/92 161/123/92 +f 108/125/93 67/129/93 68/130/93 162/126/93 +f 68/130/94 67/129/94 109/128/94 163/127/94 +f 110/131/95 128/132/95 160/122/95 162/126/95 +f 161/123/96 129/133/96 111/134/96 163/127/96 +f 128/132/97 179/135/97 158/118/97 160/122/97 +f 159/119/98 180/136/98 129/133/98 161/123/98 +f 126/137/99 156/114/99 158/118/99 179/135/99 +f 159/119/100 157/115/100 127/138/100 180/136/100 +f 124/139/101 154/110/101 156/114/101 126/137/101 +f 157/115/102 155/111/102 125/140/102 127/138/102 +f 122/141/103 152/106/103 154/110/103 124/139/103 +f 155/111/104 153/107/104 123/142/104 125/140/104 +f 120/143/105 150/102/105 152/106/105 122/141/105 +f 153/107/106 151/103/106 121/144/106 123/142/106 +f 118/145/107 148/98/107 150/102/107 120/143/107 +f 151/103/108 149/99/108 119/146/108 121/144/108 +f 116/147/109 146/91/109 148/98/109 118/145/109 +f 149/99/110 147/93/110 117/148/110 119/146/110 +f 114/149/111 164/92/111 146/91/111 116/147/111 +f 147/93/112 165/96/112 115/150/112 117/148/112 +f 114/149/113 181/151/113 177/152/113 164/92/113 +f 177/152/114 182/153/114 115/150/114 165/96/114 +f 110/131/115 162/126/115 68/130/115 112/154/115 +f 68/130/116 163/127/116 111/134/116 113/155/116 +f 112/154/117 68/130/117 178/156/117 183/157/117 +f 178/156/118 68/130/118 113/155/118 184/158/118 +f 177/152/119 181/151/119 183/157/119 178/156/119 +f 184/158/120 182/153/120 177/152/120 178/156/120 +f 135/159/121 137/160/121 176/69/121 174/68/121 +f 176/69/122 137/160/122 136/161/122 175/71/122 +f 133/162/123 135/159/123 174/68/123 172/74/123 +f 175/71/124 136/161/124 134/163/124 173/75/124 +f 131/164/125 133/162/125 172/74/125 170/78/125 +f 173/75/126 134/163/126 132/165/126 171/79/126 +f 166/86/127 187/166/127 185/167/127 168/82/127 +f 186/168/128 188/169/128 167/87/128 169/83/128 +f 131/164/129 170/78/129 168/82/129 185/167/129 +f 169/83/130 171/79/130 132/165/130 186/168/130 +f 144/170/131 190/171/131 189/172/131 187/166/131 +f 189/172/132 190/171/132 145/173/132 188/169/132 +f 185/167/133 187/166/133 189/172/133 69/174/133 +f 189/172/134 188/169/134 186/168/134 69/174/134 +f 130/175/135 131/164/135 185/167/135 69/174/135 +f 186/168/135 132/165/135 130/175/135 69/174/135 +f 142/176/136 193/177/136 191/178/136 144/170/136 +f 192/179/137 194/180/137 143/181/137 145/173/137 +f 140/182/138 195/183/138 193/177/138 142/176/138 +f 194/180/139 196/184/139 141/185/139 143/181/139 +f 139/186/140 197/187/140 195/183/140 140/182/140 +f 196/184/141 198/188/141 139/186/141 141/185/141 +f 138/189/142 71/190/142 197/187/142 139/186/142 +f 198/188/143 71/190/143 138/189/143 139/186/143 +f 190/171/144 144/170/144 191/178/144 70/191/144 +f 192/179/145 145/173/145 190/171/145 70/191/145 +f 70/191/146 191/178/146 206/192/146 208/193/146 +f 207/194/147 192/179/147 70/191/147 208/193/147 +f 71/190/148 199/195/148 200/196/148 197/187/148 +f 201/197/149 199/195/149 71/190/149 198/188/149 +f 197/187/150 200/196/150 202/198/150 195/183/150 +f 203/199/151 201/197/151 198/188/151 196/184/151 +f 195/183/152 202/198/152 204/200/152 193/177/152 +f 205/201/153 203/199/153 196/184/153 194/180/153 +f 193/177/154 204/200/154 206/192/154 191/178/154 +f 207/194/155 205/201/155 194/180/155 192/179/155 +f 199/195/156 204/200/156 202/198/156 200/196/156 +f 203/199/157 205/201/157 199/195/157 201/197/157 +f 199/195/158 208/193/158 206/192/158 204/200/158 +f 207/194/159 208/193/159 199/195/159 205/201/159 +f 139/186/160 140/182/160 164/92/160 177/152/160 +f 165/96/161 141/185/161 139/186/161 177/152/161 +f 140/182/162 142/176/162 211/202/162 164/92/162 +f 212/203/163 143/181/163 141/185/163 165/96/163 +f 142/176/164 144/170/164 213/204/164 211/202/164 +f 214/205/165 145/173/165 143/181/165 212/203/165 +f 144/170/166 187/166/166 166/86/166 213/204/166 +f 167/87/167 188/169/167 145/173/167 214/205/167 +f 81/85/168 209/206/168 213/204/168 166/86/168 +f 214/205/169 210/207/169 82/88/169 167/87/169 +f 209/206/170 215/208/170 211/202/170 213/204/170 +f 212/203/171 216/209/171 210/207/171 214/205/171 +f 79/89/172 164/92/172 211/202/172 215/208/172 +f 212/203/173 165/96/173 80/95/173 216/209/173 +f 131/164/174 130/175/174 72/210/174 222/211/174 +f 72/210/175 130/175/175 132/165/175 223/212/175 +f 133/162/176 131/164/176 222/211/176 220/213/176 +f 223/212/177 132/165/177 134/163/177 221/214/177 +f 135/159/178 133/162/178 220/213/178 218/215/178 +f 221/214/179 134/163/179 136/161/179 219/216/179 +f 137/160/180 135/159/180 218/215/180 217/217/180 +f 219/216/181 136/161/181 137/160/181 217/217/181 +f 217/217/182 218/215/182 229/218/182 231/219/182 +f 230/220/183 219/216/183 217/217/183 231/219/183 +f 218/215/184 220/213/184 227/221/184 229/218/184 +f 228/222/185 221/214/185 219/216/185 230/220/185 +f 220/213/186 222/211/186 225/223/186 227/221/186 +f 226/224/187 223/212/187 221/214/187 228/222/187 +f 222/211/188 72/210/188 224/225/188 225/223/188 +f 224/225/189 72/210/189 223/212/189 226/224/189 +f 224/225/190 231/219/190 229/218/190 225/223/190 +f 230/220/191 231/219/191 224/225/191 226/224/191 +f 225/223/192 229/218/192 227/221/192 +f 228/222/193 230/220/193 226/224/193 +f 183/157/194 181/151/194 234/226/194 232/227/194 +f 235/228/195 182/153/195 184/158/195 233/229/195 +f 112/154/196 183/157/196 232/227/196 254/230/196 +f 233/229/197 184/158/197 113/155/197 255/231/197 +f 110/131/198 112/154/198 254/230/198 256/232/198 +f 255/231/199 113/155/199 111/134/199 257/233/199 +f 181/151/200 114/149/200 252/234/200 234/226/200 +f 253/235/201 115/150/201 182/153/201 235/228/201 +f 114/149/202 116/147/202 250/236/202 252/234/202 +f 251/237/203 117/148/203 115/150/203 253/235/203 +f 116/147/204 118/145/204 248/238/204 250/236/204 +f 249/239/205 119/146/205 117/148/205 251/237/205 +f 118/145/206 120/143/206 246/240/206 248/238/206 +f 247/241/207 121/144/207 119/146/207 249/239/207 +f 120/143/208 122/141/208 244/242/208 246/240/208 +f 245/243/209 123/142/209 121/144/209 247/241/209 +f 122/141/210 124/139/210 242/244/210 244/242/210 +f 243/245/211 125/140/211 123/142/211 245/243/211 +f 124/139/212 126/137/212 240/246/212 242/244/212 +f 241/247/213 127/138/213 125/140/213 243/245/213 +f 126/137/214 179/135/214 236/248/214 240/246/214 +f 237/249/215 180/136/215 127/138/215 241/247/215 +f 179/135/216 128/132/216 238/250/216 236/248/216 +f 239/251/217 129/133/217 180/136/217 237/249/217 +f 128/132/218 110/131/218 256/232/218 238/250/218 +f 257/233/219 111/134/219 129/133/219 239/251/219 +f 238/250/220 256/232/220 258/252/220 276/253/220 +f 259/254/221 257/233/221 239/251/221 277/255/221 +f 236/248/222 238/250/222 276/253/222 278/256/222 +f 277/255/223 239/251/223 237/249/223 279/257/223 +f 240/246/224 236/248/224 278/256/224 274/258/224 +f 279/257/225 237/249/225 241/247/225 275/259/225 +f 242/244/226 240/246/226 274/258/226 272/260/226 +f 275/259/227 241/247/227 243/245/227 273/261/227 +f 244/242/228 242/244/228 272/260/228 270/262/228 +f 273/261/229 243/245/229 245/243/229 271/263/229 +f 246/240/230 244/242/230 270/262/230 268/264/230 +f 271/263/231 245/243/231 247/241/231 269/265/231 +f 248/238/232 246/240/232 268/264/232 266/266/232 +f 269/265/233 247/241/233 249/239/233 267/267/233 +f 250/236/234 248/238/234 266/266/234 264/268/234 +f 267/267/235 249/239/235 251/237/235 265/269/235 +f 252/234/236 250/236/236 264/268/236 262/270/236 +f 265/269/237 251/237/237 253/235/237 263/271/237 +f 234/226/238 252/234/238 262/270/238 280/272/238 +f 263/271/239 253/235/239 235/228/239 281/273/239 +f 256/232/240 254/230/240 260/274/240 258/252/240 +f 261/275/241 255/231/241 257/233/241 259/254/241 +f 254/230/242 232/227/242 282/276/242 260/274/242 +f 283/277/243 233/229/243 255/231/243 261/275/243 +f 232/227/244 234/226/244 280/272/244 282/276/244 +f 281/273/245 235/228/245 233/229/245 283/277/245 +f 67/129/246 108/125/246 284/278/246 73/279/246 +f 285/280/247 109/128/247 67/129/247 73/279/247 +f 108/125/248 106/121/248 286/281/248 284/278/248 +f 287/282/249 107/124/249 109/128/249 285/280/249 +f 106/121/250 104/117/250 288/283/250 286/281/250 +f 289/284/251 105/120/251 107/124/251 287/282/251 +f 104/117/252 102/113/252 290/285/252 288/283/252 +f 291/286/253 103/116/253 105/120/253 289/284/253 +f 102/113/254 100/109/254 292/287/254 290/285/254 +f 293/288/255 101/112/255 103/116/255 291/286/255 +f 100/109/256 98/105/256 294/289/256 292/287/256 +f 295/290/257 99/108/257 101/112/257 293/288/257 +f 98/105/258 96/101/258 296/291/258 294/289/258 +f 297/292/259 97/104/259 99/108/259 295/290/259 +f 96/101/260 94/97/260 298/293/260 296/291/260 +f 299/294/261 95/100/261 97/104/261 297/292/261 +f 94/97/262 92/90/262 300/295/262 298/293/262 +f 301/296/263 93/94/263 95/100/263 299/294/263 +f 308/297/264 309/298/264 328/299/264 338/300/264 +f 329/301/265 309/302/265 308/303/265 339/304/265 +f 307/305/266 308/297/266 338/300/266 336/306/266 +f 339/304/267 308/303/267 307/307/267 337/308/267 +f 306/309/268 307/305/268 336/306/268 340/310/268 +f 337/308/269 307/307/269 306/309/269 341/311/269 +f 89/67/270 91/70/270 306/309/270 340/310/270 +f 306/309/271 91/70/271 90/72/271 341/311/271 +f 87/73/272 89/67/272 340/310/272 334/312/272 +f 341/311/273 90/72/273 88/76/273 335/313/273 +f 85/77/274 87/73/274 334/312/274 330/314/274 +f 335/313/275 88/76/275 86/80/275 331/315/275 +f 83/81/276 85/77/276 330/314/276 332/316/276 +f 331/315/277 86/80/277 84/84/277 333/317/277 +f 330/314/278 336/306/278 338/300/278 332/316/278 +f 339/304/279 337/308/279 331/315/279 333/317/279 +f 330/314/280 334/312/280 340/310/280 336/306/280 +f 341/311/281 335/313/281 331/315/281 337/308/281 +f 326/318/282 332/316/282 338/300/282 328/299/282 +f 339/304/283 333/317/283 327/319/283 329/301/283 +f 81/85/284 83/81/284 332/316/284 326/318/284 +f 333/317/285 84/84/285 82/88/285 327/319/285 +f 209/206/286 342/320/286 344/321/286 215/208/286 +f 345/322/287 343/323/287 210/207/287 216/209/287 +f 81/85/288 326/318/288 342/320/288 209/206/288 +f 343/323/289 327/319/289 82/88/289 210/207/289 +f 79/89/290 215/208/290 344/321/290 346/324/290 +f 345/322/291 216/209/291 80/95/291 347/325/291 +f 79/89/292 346/324/292 300/295/292 92/90/292 +f 301/296/293 347/325/293 80/95/293 93/94/293 +f 77/326/294 324/327/294 352/328/294 304/329/294 +f 353/330/295 325/331/295 77/332/295 304/333/295 +f 304/329/296 352/328/296 350/334/296 78/335/296 +f 351/336/297 353/330/297 304/333/297 78/337/297 +f 78/335/298 350/334/298 348/338/298 305/339/298 +f 349/340/299 351/336/299 78/337/299 305/341/299 +f 305/339/300 348/338/300 328/299/300 309/298/300 +f 329/301/301 349/340/301 305/341/301 309/302/301 +f 326/318/302 328/299/302 348/338/302 342/320/302 +f 349/340/303 329/301/303 327/319/303 343/323/303 +f 296/291/304 298/293/304 318/342/304 310/343/304 +f 319/344/305 299/294/305 297/292/305 311/345/305 +f 76/346/306 316/347/306 324/327/306 77/326/306 +f 325/331/307 317/348/307 76/349/307 77/332/307 +f 302/350/308 358/351/308 356/352/308 303/353/308 +f 357/354/309 359/355/309 302/356/309 303/357/309 +f 303/353/310 356/352/310 354/358/310 75/359/310 +f 355/360/311 357/354/311 303/357/311 75/361/311 +f 75/359/312 354/358/312 316/347/312 76/346/312 +f 317/348/313 355/360/313 75/361/313 76/349/313 +f 292/362/314 294/289/314 362/363/314 364/364/314 +f 363/365/315 295/290/315 293/366/315 365/367/315 +f 364/364/316 362/363/316 368/368/316 366/369/316 +f 369/370/317 363/365/317 365/367/317 367/371/317 +f 366/369/318 368/368/318 370/372/318 372/373/318 +f 371/374/319 369/370/319 367/371/319 373/375/319 +f 372/373/320 370/372/320 376/376/320 374/377/320 +f 377/378/321 371/374/321 373/375/321 375/379/321 +f 314/380/322 378/381/322 374/377/322 376/376/322 +f 375/379/323 379/382/323 315/383/323 377/378/323 +f 316/347/324 354/358/324 374/377/324 378/381/324 +f 375/379/325 355/360/325 317/348/325 379/382/325 +f 354/358/326 356/352/326 372/373/326 374/377/326 +f 373/375/327 357/354/327 355/360/327 375/379/327 +f 356/352/328 358/351/328 366/369/328 372/373/328 +f 367/371/329 359/355/329 357/354/329 373/375/329 +f 358/351/330 360/384/330 364/364/330 366/369/330 +f 365/367/331 361/385/331 359/355/331 367/371/331 +f 290/386/332 292/362/332 364/364/332 360/384/332 +f 365/367/333 293/366/333 291/387/333 361/385/333 +f 74/388/334 360/384/334 358/351/334 302/350/334 +f 359/355/335 361/385/335 74/389/335 302/356/335 +f 284/390/336 286/391/336 288/392/336 290/386/336 +f 289/393/337 287/394/337 285/395/337 291/387/337 +f 284/390/338 290/386/338 360/384/338 74/388/338 +f 361/385/339 291/387/339 285/395/339 74/389/339 +f 73/396/340 284/390/340 74/388/340 +f 74/389/341 285/395/341 73/397/341 +f 294/289/342 296/291/342 310/343/342 362/363/342 +f 311/345/343 297/292/343 295/290/343 363/365/343 +f 310/343/344 312/398/344 368/368/344 362/363/344 +f 369/370/345 313/399/345 311/345/345 363/365/345 +f 312/398/346 382/400/346 370/372/346 368/368/346 +f 371/374/347 383/401/347 313/399/347 369/370/347 +f 314/380/348 376/376/348 370/372/348 382/400/348 +f 371/374/349 377/378/349 315/383/349 383/401/349 +f 348/338/350 350/334/350 386/402/350 384/403/350 +f 387/404/351 351/336/351 349/340/351 385/405/351 +f 318/342/352 384/403/352 386/402/352 320/406/352 +f 387/404/353 385/405/353 319/344/353 321/407/353 +f 298/293/354 300/295/354 384/403/354 318/342/354 +f 385/405/355 301/296/355 299/294/355 319/344/355 +f 300/295/356 344/321/356 342/320/356 384/403/356 +f 343/323/357 345/322/357 301/296/357 385/405/357 +f 342/320/358 348/338/358 384/403/358 +f 385/405/359 349/340/359 343/323/359 +f 300/295/360 346/324/360 344/321/360 +f 345/322/361 347/325/361 301/296/361 +f 314/380/362 322/408/362 380/409/362 378/381/362 +f 381/410/363 323/411/363 315/383/363 379/382/363 +f 316/347/364 378/381/364 380/409/364 324/327/364 +f 381/410/365 379/382/365 317/348/365 325/331/365 +f 320/406/366 386/402/366 380/409/366 322/408/366 +f 381/410/367 387/404/367 321/407/367 323/411/367 +f 350/334/368 352/328/368 380/409/368 386/402/368 +f 381/410/369 353/330/369 351/336/369 387/404/369 +f 324/327/370 380/409/370 352/328/370 +f 353/330/371 381/410/371 325/331/371 +f 400/412/372 388/413/372 414/414/372 402/415/372 +f 415/416/373 389/417/373 401/418/373 403/419/373 +f 400/412/374 402/415/374 404/420/374 398/421/374 +f 405/422/375 403/419/375 401/418/375 399/423/375 +f 398/421/376 404/420/376 406/424/376 396/425/376 +f 407/426/377 405/422/377 399/423/377 397/427/377 +f 396/425/378 406/424/378 408/428/378 394/429/378 +f 409/430/379 407/426/379 397/427/379 395/431/379 +f 394/429/380 408/428/380 410/432/380 392/433/380 +f 411/434/381 409/430/381 395/431/381 393/435/381 +f 392/433/382 410/432/382 412/436/382 390/437/382 +f 413/438/383 411/434/383 393/435/383 391/439/383 +f 410/432/384 420/440/384 418/441/384 412/436/384 +f 419/442/385 421/443/385 411/434/385 413/438/385 +f 408/428/386 422/444/386 420/440/386 410/432/386 +f 421/443/387 423/445/387 409/430/387 411/434/387 +f 406/424/388 424/446/388 422/444/388 408/428/388 +f 423/445/389 425/447/389 407/426/389 409/430/389 +f 404/420/390 426/448/390 424/446/390 406/424/390 +f 425/447/391 427/449/391 405/422/391 407/426/391 +f 402/415/392 428/450/392 426/448/392 404/420/392 +f 427/449/393 429/451/393 403/419/393 405/422/393 +f 402/415/394 414/414/394 416/452/394 428/450/394 +f 417/453/395 415/416/395 403/419/395 429/451/395 +f 318/342/396 320/406/396 444/454/396 442/455/396 +f 445/456/397 321/407/397 319/344/397 443/457/397 +f 320/458/398 390/437/398 412/436/398 444/459/398 +f 413/438/399 391/439/399 321/460/399 445/461/399 +f 310/343/400 318/342/400 442/455/400 312/398/400 +f 443/457/401 319/344/401 311/345/401 313/399/401 +f 382/462/402 430/463/402 414/414/402 388/413/402 +f 415/416/403 431/464/403 383/465/403 389/417/403 +f 412/436/404 418/441/404 440/466/404 444/459/404 +f 441/467/405 419/442/405 413/438/405 445/461/405 +f 438/468/406 446/469/406 444/459/406 440/466/406 +f 445/461/407 447/470/407 439/471/407 441/467/407 +f 434/472/408 446/469/408 438/468/408 436/473/408 +f 439/471/409 447/470/409 435/474/409 437/475/409 +f 432/476/410 448/477/410 446/469/410 434/472/410 +f 447/470/411 449/478/411 433/479/411 435/474/411 +f 430/463/412 448/477/412 432/476/412 450/480/412 +f 433/479/413 449/478/413 431/464/413 451/481/413 +f 414/414/414 430/463/414 450/480/414 416/452/414 +f 451/481/415 431/464/415 415/416/415 417/453/415 +f 312/398/416 448/482/416 430/483/416 382/400/416 +f 431/484/417 449/485/417 313/399/417 383/401/417 +f 312/398/418 442/455/418 446/486/418 448/482/418 +f 447/487/419 443/457/419 313/399/419 449/485/419 +f 442/455/420 444/454/420 446/486/420 +f 447/487/421 445/456/421 443/457/421 +f 416/452/422 450/480/422 452/488/422 476/489/422 +f 453/490/423 451/481/423 417/453/423 477/491/423 +f 450/480/424 432/476/424 462/492/424 452/488/424 +f 463/493/425 433/479/425 451/481/425 453/490/425 +f 432/476/426 434/472/426 460/494/426 462/492/426 +f 461/495/427 435/474/427 433/479/427 463/493/427 +f 434/472/428 436/473/428 458/496/428 460/494/428 +f 459/497/429 437/475/429 435/474/429 461/495/429 +f 436/473/430 438/468/430 456/498/430 458/496/430 +f 457/499/431 439/471/431 437/475/431 459/497/431 +f 438/468/432 440/466/432 454/500/432 456/498/432 +f 455/501/433 441/467/433 439/471/433 457/499/433 +f 440/466/434 418/441/434 474/502/434 454/500/434 +f 475/503/435 419/442/435 441/467/435 455/501/435 +f 428/450/436 416/452/436 476/489/436 464/504/436 +f 477/491/437 417/453/437 429/451/437 465/505/437 +f 426/448/438 428/450/438 464/504/438 466/506/438 +f 465/505/439 429/451/439 427/449/439 467/507/439 +f 424/446/440 426/448/440 466/506/440 468/508/440 +f 467/507/441 427/449/441 425/447/441 469/509/441 +f 422/444/442 424/446/442 468/508/442 470/510/442 +f 469/509/443 425/447/443 423/445/443 471/511/443 +f 420/440/444 422/444/444 470/510/444 472/512/444 +f 471/511/445 423/445/445 421/443/445 473/513/445 +f 418/441/446 420/440/446 472/512/446 474/502/446 +f 473/513/447 421/443/447 419/442/447 475/503/447 +f 458/496/448 456/498/448 480/514/448 478/515/448 +f 481/516/449 457/499/449 459/497/449 479/517/449 +f 478/515/450 480/514/450 482/518/450 484/519/450 +f 483/520/451 481/516/451 479/517/451 485/521/451 +f 484/519/452 482/518/452 488/522/452 486/523/452 +f 489/524/453 483/520/453 485/521/453 487/525/453 +f 486/523/454 488/522/454 490/526/454 492/527/454 +f 491/528/455 489/524/455 487/525/455 493/529/455 +f 464/504/456 476/489/456 486/523/456 492/527/456 +f 487/525/457 477/491/457 465/505/457 493/529/457 +f 452/488/458 484/519/458 486/523/458 476/489/458 +f 487/525/459 485/521/459 453/490/459 477/491/459 +f 452/488/460 462/492/460 478/515/460 484/519/460 +f 479/517/461 463/493/461 453/490/461 485/521/461 +f 458/496/462 478/515/462 462/492/462 460/494/462 +f 463/493/463 479/517/463 459/497/463 461/495/463 +f 454/500/464 474/502/464 480/514/464 456/498/464 +f 481/516/465 475/503/465 455/501/465 457/499/465 +f 472/512/466 482/518/466 480/514/466 474/502/466 +f 481/516/467 483/520/467 473/513/467 475/503/467 +f 470/510/468 488/522/468 482/518/468 472/512/468 +f 483/520/469 489/524/469 471/511/469 473/513/469 +f 468/508/470 490/526/470 488/522/470 470/510/470 +f 489/524/471 491/528/471 469/509/471 471/511/471 +f 466/506/472 492/527/472 490/526/472 468/508/472 +f 491/528/473 493/529/473 467/507/473 469/509/473 +f 464/504/474 492/527/474 466/506/474 +f 467/507/475 493/529/475 465/505/475 +f 392/433/476 390/437/476 504/530/476 502/531/476 +f 505/532/477 391/439/477 393/435/477 503/533/477 +f 394/429/478 392/433/478 502/531/478 500/534/478 +f 503/533/479 393/435/479 395/431/479 501/535/479 +f 396/425/480 394/429/480 500/534/480 498/536/480 +f 501/535/481 395/431/481 397/427/481 499/537/481 +f 398/538/482 396/425/482 498/536/482 496/539/482 +f 499/537/483 397/427/483 399/540/483 497/541/483 +f 400/542/484 398/538/484 496/539/484 494/543/484 +f 497/541/485 399/540/485 401/544/485 495/545/485 +f 388/546/486 400/542/486 494/543/486 506/547/486 +f 495/545/487 401/544/487 389/548/487 507/549/487 +f 494/543/488 502/531/488 504/530/488 506/547/488 +f 505/532/489 503/533/489 495/545/489 507/549/489 +f 494/543/490 496/539/490 500/534/490 502/531/490 +f 501/535/491 497/541/491 495/545/491 503/533/491 +f 496/539/492 498/536/492 500/534/492 +f 501/535/493 499/537/493 497/541/493 +f 314/380/494 382/400/494 388/550/494 506/551/494 +f 389/548/495 383/552/495 315/553/495 507/549/495 +f 314/554/496 506/547/496 504/530/496 322/555/496 +f 505/532/497 507/549/497 315/553/497 323/556/497 +f 320/458/498 322/555/498 504/530/498 390/437/498 +f 505/532/499 323/556/499 321/460/499 391/439/499 diff --git a/crates/bevy_mikktspace/data/suzanne_smooth_tris.bin b/crates/bevy_mikktspace/data/suzanne_smooth_tris.bin new file mode 100644 index 0000000000000..a8bf56b9cbcb5 Binary files /dev/null and b/crates/bevy_mikktspace/data/suzanne_smooth_tris.bin differ diff --git a/crates/bevy_mikktspace/data/suzanne_smooth_tris.obj b/crates/bevy_mikktspace/data/suzanne_smooth_tris.obj new file mode 100644 index 0000000000000..a9c8eb10ba53b --- /dev/null +++ b/crates/bevy_mikktspace/data/suzanne_smooth_tris.obj @@ -0,0 +1,2541 @@ +# Blender 3.6.0 +# www.blender.org +o Suzanne +v 0.437500 0.164062 0.765625 +v -0.437500 0.164062 0.765625 +v 0.500000 0.093750 0.687500 +v -0.500000 0.093750 0.687500 +v 0.546875 0.054688 0.578125 +v -0.546875 0.054688 0.578125 +v 0.351562 -0.023438 0.617188 +v -0.351562 -0.023438 0.617188 +v 0.351562 0.031250 0.718750 +v -0.351562 0.031250 0.718750 +v 0.351562 0.132812 0.781250 +v -0.351562 0.132812 0.781250 +v 0.273438 0.164062 0.796875 +v -0.273438 0.164062 0.796875 +v 0.203125 0.093750 0.742188 +v -0.203125 0.093750 0.742188 +v 0.156250 0.054688 0.648438 +v -0.156250 0.054688 0.648438 +v 0.078125 0.242188 0.656250 +v -0.078125 0.242188 0.656250 +v 0.140625 0.242188 0.742188 +v -0.140625 0.242188 0.742188 +v 0.242188 0.242188 0.796875 +v -0.242188 0.242188 0.796875 +v 0.273438 0.328125 0.796875 +v -0.273438 0.328125 0.796875 +v 0.203125 0.390625 0.742188 +v -0.203125 0.390625 0.742188 +v 0.156250 0.437500 0.648438 +v -0.156250 0.437500 0.648438 +v 0.351562 0.515625 0.617188 +v -0.351562 0.515625 0.617188 +v 0.351562 0.453125 0.718750 +v -0.351562 0.453125 0.718750 +v 0.351562 0.359375 0.781250 +v -0.351562 0.359375 0.781250 +v 0.437500 0.328125 0.765625 +v -0.437500 0.328125 0.765625 +v 0.500000 0.390625 0.687500 +v -0.500000 0.390625 0.687500 +v 0.546875 0.437500 0.578125 +v -0.546875 0.437500 0.578125 +v 0.625000 0.242188 0.562500 +v -0.625000 0.242188 0.562500 +v 0.562500 0.242188 0.671875 +v -0.562500 0.242188 0.671875 +v 0.468750 0.242188 0.757812 +v -0.468750 0.242188 0.757812 +v 0.476562 0.242188 0.773438 +v -0.476562 0.242188 0.773438 +v 0.445312 0.335938 0.781250 +v -0.445312 0.335938 0.781250 +v 0.351562 0.375000 0.804688 +v -0.351562 0.375000 0.804688 +v 0.265625 0.335938 0.820312 +v -0.265625 0.335938 0.820312 +v 0.226562 0.242188 0.820312 +v -0.226562 0.242188 0.820312 +v 0.265625 0.156250 0.820312 +v -0.265625 0.156250 0.820312 +v 0.351562 0.242188 0.828125 +v -0.351562 0.242188 0.828125 +v 0.351562 0.117188 0.804688 +v -0.351562 0.117188 0.804688 +v 0.445312 0.156250 0.781250 +v -0.445312 0.156250 0.781250 +v 0.000000 0.429688 0.742188 +v 0.000000 0.351562 0.820312 +v 0.000000 -0.679688 0.734375 +v 0.000000 -0.320312 0.781250 +v 0.000000 -0.187500 0.796875 +v 0.000000 -0.773438 0.718750 +v 0.000000 0.406250 0.601562 +v 0.000000 0.570312 0.570312 +v 0.000000 0.898438 -0.546875 +v 0.000000 0.562500 -0.851562 +v 0.000000 0.070312 -0.828125 +v 0.000000 -0.382812 -0.351562 +v 0.203125 -0.187500 0.562500 +v -0.203125 -0.187500 0.562500 +v 0.312500 -0.437500 0.570312 +v -0.312500 -0.437500 0.570312 +v 0.351562 -0.695312 0.570312 +v -0.351562 -0.695312 0.570312 +v 0.367188 -0.890625 0.531250 +v -0.367188 -0.890625 0.531250 +v 0.328125 -0.945312 0.523438 +v -0.328125 -0.945312 0.523438 +v 0.179688 -0.968750 0.554688 +v -0.179688 -0.968750 0.554688 +v 0.000000 -0.984375 0.578125 +v 0.437500 -0.140625 0.531250 +v -0.437500 -0.140625 0.531250 +v 0.632812 -0.039062 0.539062 +v -0.632812 -0.039062 0.539062 +v 0.828125 0.148438 0.445312 +v -0.828125 0.148438 0.445312 +v 0.859375 0.429688 0.593750 +v -0.859375 0.429688 0.593750 +v 0.710938 0.484375 0.625000 +v -0.710938 0.484375 0.625000 +v 0.492188 0.601562 0.687500 +v -0.492188 0.601562 0.687500 +v 0.320312 0.757812 0.734375 +v -0.320312 0.757812 0.734375 +v 0.156250 0.718750 0.757812 +v -0.156250 0.718750 0.757812 +v 0.062500 0.492188 0.750000 +v -0.062500 0.492188 0.750000 +v 0.164062 0.414062 0.773438 +v -0.164062 0.414062 0.773438 +v 0.125000 0.304688 0.765625 +v -0.125000 0.304688 0.765625 +v 0.203125 0.093750 0.742188 +v -0.203125 0.093750 0.742188 +v 0.375000 0.015625 0.703125 +v -0.375000 0.015625 0.703125 +v 0.492188 0.062500 0.671875 +v -0.492188 0.062500 0.671875 +v 0.625000 0.187500 0.648438 +v -0.625000 0.187500 0.648438 +v 0.640625 0.296875 0.648438 +v -0.640625 0.296875 0.648438 +v 0.601562 0.375000 0.664062 +v -0.601562 0.375000 0.664062 +v 0.429688 0.437500 0.718750 +v -0.429688 0.437500 0.718750 +v 0.250000 0.468750 0.757812 +v -0.250000 0.468750 0.757812 +v 0.000000 -0.765625 0.734375 +v 0.109375 -0.718750 0.734375 +v -0.109375 -0.718750 0.734375 +v 0.117188 -0.835938 0.710938 +v -0.117188 -0.835938 0.710938 +v 0.062500 -0.882812 0.695312 +v -0.062500 -0.882812 0.695312 +v 0.000000 -0.890625 0.687500 +v 0.000000 -0.195312 0.750000 +v 0.000000 -0.140625 0.742188 +v 0.101562 -0.148438 0.742188 +v -0.101562 -0.148438 0.742188 +v 0.125000 -0.226562 0.750000 +v -0.125000 -0.226562 0.750000 +v 0.085938 -0.289062 0.742188 +v -0.085938 -0.289062 0.742188 +v 0.398438 -0.046875 0.671875 +v -0.398438 -0.046875 0.671875 +v 0.617188 0.054688 0.625000 +v -0.617188 0.054688 0.625000 +v 0.726562 0.203125 0.601562 +v -0.726562 0.203125 0.601562 +v 0.742188 0.375000 0.656250 +v -0.742188 0.375000 0.656250 +v 0.687500 0.414062 0.726562 +v -0.687500 0.414062 0.726562 +v 0.437500 0.546875 0.796875 +v -0.437500 0.546875 0.796875 +v 0.312500 0.640625 0.835938 +v -0.312500 0.640625 0.835938 +v 0.203125 0.617188 0.851562 +v -0.203125 0.617188 0.851562 +v 0.101562 0.429688 0.843750 +v -0.101562 0.429688 0.843750 +v 0.125000 -0.101562 0.812500 +v -0.125000 -0.101562 0.812500 +v 0.210938 -0.445312 0.710938 +v -0.210938 -0.445312 0.710938 +v 0.250000 -0.703125 0.687500 +v -0.250000 -0.703125 0.687500 +v 0.265625 -0.820312 0.664062 +v -0.265625 -0.820312 0.664062 +v 0.234375 -0.914062 0.632812 +v -0.234375 -0.914062 0.632812 +v 0.164062 -0.929688 0.632812 +v -0.164062 -0.929688 0.632812 +v 0.000000 -0.945312 0.640625 +v 0.000000 0.046875 0.726562 +v 0.000000 0.210938 0.765625 +v 0.328125 0.476562 0.742188 +v -0.328125 0.476562 0.742188 +v 0.164062 0.140625 0.750000 +v -0.164062 0.140625 0.750000 +v 0.132812 0.210938 0.757812 +v -0.132812 0.210938 0.757812 +v 0.117188 -0.687500 0.734375 +v -0.117188 -0.687500 0.734375 +v 0.078125 -0.445312 0.750000 +v -0.078125 -0.445312 0.750000 +v 0.000000 -0.445312 0.750000 +v 0.000000 -0.328125 0.742188 +v 0.093750 -0.273438 0.781250 +v -0.093750 -0.273438 0.781250 +v 0.132812 -0.226562 0.796875 +v -0.132812 -0.226562 0.796875 +v 0.109375 -0.132812 0.781250 +v -0.109375 -0.132812 0.781250 +v 0.039062 -0.125000 0.781250 +v -0.039062 -0.125000 0.781250 +v 0.000000 -0.203125 0.828125 +v 0.046875 -0.148438 0.812500 +v -0.046875 -0.148438 0.812500 +v 0.093750 -0.156250 0.812500 +v -0.093750 -0.156250 0.812500 +v 0.109375 -0.226562 0.828125 +v -0.109375 -0.226562 0.828125 +v 0.078125 -0.250000 0.804688 +v -0.078125 -0.250000 0.804688 +v 0.000000 -0.289062 0.804688 +v 0.257812 -0.312500 0.554688 +v -0.257812 -0.312500 0.554688 +v 0.164062 -0.242188 0.710938 +v -0.164062 -0.242188 0.710938 +v 0.179688 -0.312500 0.710938 +v -0.179688 -0.312500 0.710938 +v 0.234375 -0.250000 0.554688 +v -0.234375 -0.250000 0.554688 +v 0.000000 -0.875000 0.687500 +v 0.046875 -0.867188 0.687500 +v -0.046875 -0.867188 0.687500 +v 0.093750 -0.820312 0.710938 +v -0.093750 -0.820312 0.710938 +v 0.093750 -0.742188 0.726562 +v -0.093750 -0.742188 0.726562 +v 0.000000 -0.781250 0.656250 +v 0.093750 -0.750000 0.664062 +v -0.093750 -0.750000 0.664062 +v 0.093750 -0.812500 0.640625 +v -0.093750 -0.812500 0.640625 +v 0.046875 -0.851562 0.632812 +v -0.046875 -0.851562 0.632812 +v 0.000000 -0.859375 0.632812 +v 0.171875 0.218750 0.781250 +v -0.171875 0.218750 0.781250 +v 0.187500 0.156250 0.773438 +v -0.187500 0.156250 0.773438 +v 0.335938 0.429688 0.757812 +v -0.335938 0.429688 0.757812 +v 0.273438 0.421875 0.773438 +v -0.273438 0.421875 0.773438 +v 0.421875 0.398438 0.773438 +v -0.421875 0.398438 0.773438 +v 0.562500 0.351562 0.695312 +v -0.562500 0.351562 0.695312 +v 0.585938 0.289062 0.687500 +v -0.585938 0.289062 0.687500 +v 0.578125 0.195312 0.679688 +v -0.578125 0.195312 0.679688 +v 0.476562 0.101562 0.718750 +v -0.476562 0.101562 0.718750 +v 0.375000 0.062500 0.742188 +v -0.375000 0.062500 0.742188 +v 0.226562 0.109375 0.781250 +v -0.226562 0.109375 0.781250 +v 0.179688 0.296875 0.781250 +v -0.179688 0.296875 0.781250 +v 0.210938 0.375000 0.781250 +v -0.210938 0.375000 0.781250 +v 0.234375 0.359375 0.757812 +v -0.234375 0.359375 0.757812 +v 0.195312 0.296875 0.757812 +v -0.195312 0.296875 0.757812 +v 0.242188 0.125000 0.757812 +v -0.242188 0.125000 0.757812 +v 0.375000 0.085938 0.726562 +v -0.375000 0.085938 0.726562 +v 0.460938 0.117188 0.703125 +v -0.460938 0.117188 0.703125 +v 0.546875 0.210938 0.671875 +v -0.546875 0.210938 0.671875 +v 0.554688 0.281250 0.671875 +v -0.554688 0.281250 0.671875 +v 0.531250 0.335938 0.679688 +v -0.531250 0.335938 0.679688 +v 0.414062 0.390625 0.750000 +v -0.414062 0.390625 0.750000 +v 0.281250 0.398438 0.765625 +v -0.281250 0.398438 0.765625 +v 0.335938 0.406250 0.750000 +v -0.335938 0.406250 0.750000 +v 0.203125 0.171875 0.750000 +v -0.203125 0.171875 0.750000 +v 0.195312 0.226562 0.750000 +v -0.195312 0.226562 0.750000 +v 0.109375 0.460938 0.609375 +v -0.109375 0.460938 0.609375 +v 0.195312 0.664062 0.617188 +v -0.195312 0.664062 0.617188 +v 0.335938 0.687500 0.593750 +v -0.335938 0.687500 0.593750 +v 0.484375 0.554688 0.554688 +v -0.484375 0.554688 0.554688 +v 0.679688 0.453125 0.492188 +v -0.679688 0.453125 0.492188 +v 0.796875 0.406250 0.460938 +v -0.796875 0.406250 0.460938 +v 0.773438 0.164062 0.375000 +v -0.773438 0.164062 0.375000 +v 0.601562 0.000000 0.414062 +v -0.601562 0.000000 0.414062 +v 0.437500 -0.093750 0.468750 +v -0.437500 -0.093750 0.468750 +v 0.000000 0.898438 0.289062 +v 0.000000 0.984375 -0.078125 +v 0.000000 -0.195312 -0.671875 +v 0.000000 -0.460938 0.187500 +v 0.000000 -0.976562 0.460938 +v 0.000000 -0.804688 0.343750 +v 0.000000 -0.570312 0.320312 +v 0.000000 -0.484375 0.281250 +v 0.851562 0.234375 0.054688 +v -0.851562 0.234375 0.054688 +v 0.859375 0.320312 -0.046875 +v -0.859375 0.320312 -0.046875 +v 0.773438 0.265625 -0.437500 +v -0.773438 0.265625 -0.437500 +v 0.460938 0.437500 -0.703125 +v -0.460938 0.437500 -0.703125 +v 0.734375 -0.046875 0.070312 +v -0.734375 -0.046875 0.070312 +v 0.593750 -0.125000 -0.164062 +v -0.593750 -0.125000 -0.164062 +v 0.640625 -0.007812 -0.429688 +v -0.640625 -0.007812 -0.429688 +v 0.335938 0.054688 -0.664062 +v -0.335938 0.054688 -0.664062 +v 0.234375 -0.351562 0.406250 +v -0.234375 -0.351562 0.406250 +v 0.179688 -0.414062 0.257812 +v -0.179688 -0.414062 0.257812 +v 0.289062 -0.710938 0.382812 +v -0.289062 -0.710938 0.382812 +v 0.250000 -0.500000 0.390625 +v -0.250000 -0.500000 0.390625 +v 0.328125 -0.914062 0.398438 +v -0.328125 -0.914062 0.398438 +v 0.140625 -0.757812 0.367188 +v -0.140625 -0.757812 0.367188 +v 0.125000 -0.539062 0.359375 +v -0.125000 -0.539062 0.359375 +v 0.164062 -0.945312 0.437500 +v -0.164062 -0.945312 0.437500 +v 0.218750 -0.281250 0.429688 +v -0.218750 -0.281250 0.429688 +v 0.210938 -0.226562 0.468750 +v -0.210938 -0.226562 0.468750 +v 0.203125 -0.171875 0.500000 +v -0.203125 -0.171875 0.500000 +v 0.210938 -0.390625 0.164062 +v -0.210938 -0.390625 0.164062 +v 0.296875 -0.312500 -0.265625 +v -0.296875 -0.312500 -0.265625 +v 0.343750 -0.148438 -0.539062 +v -0.343750 -0.148438 -0.539062 +v 0.453125 0.867188 -0.382812 +v -0.453125 0.867188 -0.382812 +v 0.453125 0.929688 -0.070312 +v -0.453125 0.929688 -0.070312 +v 0.453125 0.851562 0.234375 +v -0.453125 0.851562 0.234375 +v 0.460938 0.523438 0.429688 +v -0.460938 0.523438 0.429688 +v 0.726562 0.406250 0.335938 +v -0.726562 0.406250 0.335938 +v 0.632812 0.453125 0.281250 +v -0.632812 0.453125 0.281250 +v 0.640625 0.703125 0.054688 +v -0.640625 0.703125 0.054688 +v 0.796875 0.562500 0.125000 +v -0.796875 0.562500 0.125000 +v 0.796875 0.617188 -0.117188 +v -0.796875 0.617188 -0.117188 +v 0.640625 0.750000 -0.195312 +v -0.640625 0.750000 -0.195312 +v 0.640625 0.679688 -0.445312 +v -0.640625 0.679688 -0.445312 +v 0.796875 0.539062 -0.359375 +v -0.796875 0.539062 -0.359375 +v 0.617188 0.328125 -0.585938 +v -0.617188 0.328125 -0.585938 +v 0.484375 0.023438 -0.546875 +v -0.484375 0.023438 -0.546875 +v 0.820312 0.328125 -0.203125 +v -0.820312 0.328125 -0.203125 +v 0.406250 -0.171875 0.148438 +v -0.406250 -0.171875 0.148438 +v 0.429688 -0.195312 -0.210938 +v -0.429688 -0.195312 -0.210938 +v 0.890625 0.406250 -0.234375 +v -0.890625 0.406250 -0.234375 +v 0.773438 -0.140625 -0.125000 +v -0.773438 -0.140625 -0.125000 +v 1.039062 -0.101562 -0.328125 +v -1.039062 -0.101562 -0.328125 +v 1.281250 0.054688 -0.429688 +v -1.281250 0.054688 -0.429688 +v 1.351562 0.320312 -0.421875 +v -1.351562 0.320312 -0.421875 +v 1.234375 0.507812 -0.421875 +v -1.234375 0.507812 -0.421875 +v 1.023438 0.476562 -0.312500 +v -1.023438 0.476562 -0.312500 +v 1.015625 0.414062 -0.289062 +v -1.015625 0.414062 -0.289062 +v 1.187500 0.437500 -0.390625 +v -1.187500 0.437500 -0.390625 +v 1.265625 0.289062 -0.406250 +v -1.265625 0.289062 -0.406250 +v 1.210938 0.078125 -0.406250 +v -1.210938 0.078125 -0.406250 +v 1.031250 -0.039062 -0.304688 +v -1.031250 -0.039062 -0.304688 +v 0.828125 -0.070312 -0.132812 +v -0.828125 -0.070312 -0.132812 +v 0.921875 0.359375 -0.218750 +v -0.921875 0.359375 -0.218750 +v 0.945312 0.304688 -0.289062 +v -0.945312 0.304688 -0.289062 +v 0.882812 -0.023438 -0.210938 +v -0.882812 -0.023438 -0.210938 +v 1.039062 0.000000 -0.367188 +v -1.039062 0.000000 -0.367188 +v 1.187500 0.093750 -0.445312 +v -1.187500 0.093750 -0.445312 +v 1.234375 0.250000 -0.445312 +v -1.234375 0.250000 -0.445312 +v 1.171875 0.359375 -0.437500 +v -1.171875 0.359375 -0.437500 +v 1.023438 0.343750 -0.359375 +v -1.023438 0.343750 -0.359375 +v 0.843750 0.289062 -0.210938 +v -0.843750 0.289062 -0.210938 +v 0.835938 0.171875 -0.273438 +v -0.835938 0.171875 -0.273438 +v 0.757812 0.093750 -0.273438 +v -0.757812 0.093750 -0.273438 +v 0.820312 0.085938 -0.273438 +v -0.820312 0.085938 -0.273438 +v 0.843750 0.015625 -0.273438 +v -0.843750 0.015625 -0.273438 +v 0.812500 -0.015625 -0.273438 +v -0.812500 -0.015625 -0.273438 +v 0.726562 0.000000 -0.070312 +v -0.726562 0.000000 -0.070312 +v 0.718750 -0.023438 -0.171875 +v -0.718750 -0.023438 -0.171875 +v 0.718750 0.039062 -0.187500 +v -0.718750 0.039062 -0.187500 +v 0.796875 0.203125 -0.210938 +v -0.796875 0.203125 -0.210938 +v 0.890625 0.242188 -0.265625 +v -0.890625 0.242188 -0.265625 +v 0.890625 0.234375 -0.320312 +v -0.890625 0.234375 -0.320312 +v 0.812500 -0.015625 -0.320312 +v -0.812500 -0.015625 -0.320312 +v 0.851562 0.015625 -0.320312 +v -0.851562 0.015625 -0.320312 +v 0.828125 0.078125 -0.320312 +v -0.828125 0.078125 -0.320312 +v 0.765625 0.093750 -0.320312 +v -0.765625 0.093750 -0.320312 +v 0.843750 0.171875 -0.320312 +v -0.843750 0.171875 -0.320312 +v 1.039062 0.328125 -0.414062 +v -1.039062 0.328125 -0.414062 +v 1.187500 0.343750 -0.484375 +v -1.187500 0.343750 -0.484375 +v 1.257812 0.242188 -0.492188 +v -1.257812 0.242188 -0.492188 +v 1.210938 0.085938 -0.484375 +v -1.210938 0.085938 -0.484375 +v 1.046875 0.000000 -0.421875 +v -1.046875 0.000000 -0.421875 +v 0.882812 -0.015625 -0.265625 +v -0.882812 -0.015625 -0.265625 +v 0.953125 0.289062 -0.343750 +v -0.953125 0.289062 -0.343750 +v 0.890625 0.109375 -0.328125 +v -0.890625 0.109375 -0.328125 +v 0.937500 0.062500 -0.335938 +v -0.937500 0.062500 -0.335938 +v 1.000000 0.125000 -0.367188 +v -1.000000 0.125000 -0.367188 +v 0.960938 0.171875 -0.351562 +v -0.960938 0.171875 -0.351562 +v 1.015625 0.234375 -0.375000 +v -1.015625 0.234375 -0.375000 +v 1.054688 0.187500 -0.382812 +v -1.054688 0.187500 -0.382812 +v 1.109375 0.210938 -0.390625 +v -1.109375 0.210938 -0.390625 +v 1.085938 0.273438 -0.390625 +v -1.085938 0.273438 -0.390625 +v 1.023438 0.437500 -0.484375 +v -1.023438 0.437500 -0.484375 +v 1.250000 0.468750 -0.546875 +v -1.250000 0.468750 -0.546875 +v 1.367188 0.296875 -0.500000 +v -1.367188 0.296875 -0.500000 +v 1.312500 0.054688 -0.531250 +v -1.312500 0.054688 -0.531250 +v 1.039062 -0.085938 -0.492188 +v -1.039062 -0.085938 -0.492188 +v 0.789062 -0.125000 -0.328125 +v -0.789062 -0.125000 -0.328125 +v 0.859375 0.382812 -0.382812 +v -0.859375 0.382812 -0.382812 +vn 0.9693 -0.0118 0.2456 +vn 0.6076 -0.5104 0.6085 +vn 0.8001 -0.0029 0.5999 +vn -0.6076 -0.5104 0.6085 +vn -0.9693 -0.0118 0.2456 +vn -0.8001 -0.0029 0.5999 +vn 0.6802 -0.5463 0.4888 +vn 0.8682 -0.0048 0.4961 +vn -0.6802 -0.5463 0.4888 +vn -0.8682 -0.0048 0.4961 +vn 0.1193 -0.8712 0.4763 +vn -0.1193 -0.8712 0.4763 +vn 0.7290 -0.6566 0.1934 +vn 0.0995 -0.7515 0.6522 +vn -0.0995 -0.7515 0.6522 +vn -0.7290 -0.6566 0.1934 +vn 0.0314 -0.9670 0.2529 +vn -0.4563 -0.5362 0.7101 +vn 0.4563 -0.5362 0.7101 +vn -0.0314 -0.9670 0.2529 +vn -0.5539 -0.6332 0.5406 +vn 0.5539 -0.6332 0.5406 +vn -0.6899 -0.0041 0.7239 +vn 0.6899 -0.0041 0.7239 +vn 0.8097 -0.0070 0.5868 +vn -0.6506 -0.6883 0.3210 +vn 0.6506 -0.6883 0.3210 +vn -0.9521 -0.0102 0.3057 +vn -0.4560 0.5222 0.7207 +vn 0.4560 0.5222 0.7207 +vn 0.9521 -0.0102 0.3057 +vn -0.8097 -0.0070 0.5868 +vn 0.5306 0.6258 0.5717 +vn 0.1031 0.7402 0.6644 +vn -0.5306 0.6258 0.5717 +vn -0.1031 0.7402 0.6644 +vn -0.1257 0.8416 0.5253 +vn 0.0258 0.9726 0.2312 +vn -0.6644 0.6821 0.3056 +vn -0.0258 0.9726 0.2312 +vn 0.7364 0.6521 0.1803 +vn -0.7364 0.6521 0.1803 +vn -0.6102 0.4956 0.6181 +vn 0.6102 0.4956 0.6181 +vn 0.1257 0.8416 0.5253 +vn -0.6682 0.5371 0.5148 +vn 0.6682 0.5371 0.5148 +vn 0.9645 -0.0127 0.2639 +vn -0.9645 -0.0127 0.2639 +vn -0.7216 0.6556 0.2224 +vn 0.7216 0.6556 0.2224 +vn -0.0432 0.9389 0.3415 +vn 0.0432 0.9389 0.3415 +vn 0.6644 0.6821 0.3056 +vn 0.6237 0.6285 0.4647 +vn -0.6237 0.6285 0.4647 +vn 0.9270 -0.0130 0.3749 +vn -0.6159 -0.6366 0.4641 +vn -0.9270 -0.0130 0.3749 +vn 0.6159 -0.6366 0.4641 +vn 0.0426 -0.9404 0.3375 +vn -0.0426 -0.9404 0.3375 +vn 0.7152 -0.6625 0.2227 +vn -0.7152 -0.6625 0.2227 +vn 0.1836 -0.0053 0.9830 +vn -0.1836 -0.0053 0.9830 +vn 0.1554 -0.7590 0.6323 +vn -0.0000 -0.9677 0.2523 +vn 0.1596 -0.9753 0.1529 +vn -0.1554 -0.7590 0.6323 +vn -0.0000 -0.7753 0.6316 +vn 0.3502 -0.6392 0.6847 +vn 0.5267 -0.8347 0.1611 +vn -0.3502 -0.6392 0.6847 +vn -0.1596 -0.9753 0.1529 +vn 0.9457 -0.2579 0.1977 +vn -0.9457 -0.2579 0.1977 +vn -0.5267 -0.8347 0.1611 +vn 0.9728 0.1003 0.2087 +vn 0.5557 -0.2264 0.8000 +vn -0.5557 -0.2264 0.8000 +vn -0.9728 0.1003 0.2087 +vn 0.9557 0.2492 0.1565 +vn 0.5652 -0.0297 0.8244 +vn -0.5652 -0.0297 0.8244 +vn -0.9557 0.2492 0.1565 +vn 0.8916 -0.3307 0.3095 +vn 0.3842 -0.5671 0.7286 +vn 0.0402 -0.2722 0.9614 +vn -0.3842 -0.5671 0.7286 +vn -0.8916 -0.3307 0.3095 +vn -0.0402 -0.2722 0.9614 +vn 0.5875 -0.7849 0.1970 +vn 0.3489 -0.9371 -0.0082 +vn -0.5875 -0.7849 0.1970 +vn -0.4991 -0.3761 0.7807 +vn 0.5666 -0.3188 0.7598 +vn 0.4991 -0.3761 0.7807 +vn -0.5666 -0.3188 0.7598 +vn 0.8451 0.4434 0.2985 +vn 0.9070 -0.4009 -0.1290 +vn -0.8451 0.4434 0.2985 +vn -0.4607 -0.1448 0.8757 +vn 0.5171 0.8291 0.2125 +vn 0.4607 -0.1448 0.8757 +vn -0.5171 0.8291 0.2125 +vn -0.4801 -0.1833 0.8578 +vn 0.5976 0.7847 0.1646 +vn 0.4801 -0.1833 0.8578 +vn -0.5976 0.7847 0.1646 +vn -0.3085 0.0039 0.9512 +vn 0.2666 0.2166 0.9392 +vn 0.3085 0.0039 0.9512 +vn -0.2666 0.2166 0.9392 +vn -0.6051 0.7680 0.2098 +vn 0.2313 0.9570 0.1751 +vn 0.6051 0.7680 0.2098 +vn 0.1574 0.1660 0.9735 +vn -0.8242 0.5468 0.1473 +vn -0.1574 0.1660 0.9735 +vn 0.8242 0.5468 0.1473 +vn 0.0611 -0.0253 0.9978 +vn -0.0000 0.9636 0.2673 +vn -0.0611 -0.0253 0.9978 +vn -0.0000 -0.0827 0.9966 +vn 0.2582 -0.1265 0.9578 +vn 0.3679 -0.2836 0.8856 +vn -0.2582 -0.1265 0.9578 +vn 0.1490 -0.1542 0.9767 +vn 0.2190 0.0372 0.9750 +vn -0.1490 -0.1542 0.9767 +vn 0.2254 -0.3608 0.9050 +vn -0.2190 0.0372 0.9750 +vn 0.3588 -0.1192 0.9258 +vn -0.2254 -0.3608 0.9050 +vn 0.4602 -0.1651 0.8723 +vn -0.3588 -0.1192 0.9258 +vn 0.4279 -0.3895 0.8156 +vn -0.4602 -0.1651 0.8723 +vn 0.3322 -0.3667 0.8690 +vn -0.4279 -0.3895 0.8156 +vn -0.1522 -0.2549 0.9549 +vn -0.3322 -0.3667 0.8690 +vn -0.0000 0.0643 0.9979 +vn 0.1522 -0.2549 0.9549 +vn 0.0316 -0.1782 0.9835 +vn -0.0316 -0.1782 0.9835 +vn -0.0000 -0.2220 0.9750 +vn -0.2006 -0.1350 0.9703 +vn 0.2006 -0.1350 0.9703 +vn -0.2393 -0.3012 0.9230 +vn 0.2393 -0.3012 0.9230 +vn -0.0589 -0.3784 0.9238 +vn 0.0589 -0.3784 0.9238 +vn 0.1307 -0.3187 0.9388 +vn -0.1307 -0.3187 0.9388 +vn 0.1460 -0.1202 0.9820 +vn 0.5937 0.1082 0.7974 +vn 0.1815 -0.0452 0.9823 +vn -0.1815 -0.0452 0.9823 +vn -0.5937 0.1082 0.7974 +vn -0.1460 -0.1202 0.9820 +vn -0.0000 -0.4760 0.8795 +vn 0.1341 0.0063 0.9909 +vn 0.5003 -0.4293 0.7520 +vn -0.1341 0.0063 0.9909 +vn -0.0000 -0.0000 1.0000 +vn -0.0000 -0.0341 0.9994 +vn -0.0000 -0.5870 0.8096 +vn 0.9304 -0.1242 0.3448 +vn 0.5836 -0.6929 0.4235 +vn -0.5836 -0.6929 0.4235 +vn -0.9304 -0.1242 0.3448 +vn -0.5003 -0.4293 0.7520 +vn 0.4931 -0.3412 0.8002 +vn 0.9306 -0.2353 0.2804 +vn -0.9306 -0.2353 0.2804 +vn -0.4931 -0.3412 0.8002 +vn -0.2405 0.9491 0.2036 +vn -0.1770 0.5084 0.8427 +vn 0.2405 0.9491 0.2036 +vn -0.6286 0.7688 0.1177 +vn -0.1950 0.8128 0.5489 +vn -1.0000 -0.0000 -0.0000 +vn -0.0000 -0.8654 0.5011 +vn -0.0000 -0.4815 0.8764 +vn -0.1833 -0.5864 0.7890 +vn -0.1858 0.5956 0.7815 +vn 0.1858 0.5956 0.7815 +vn 0.3611 0.4713 0.8047 +vn 0.6286 0.7688 0.1177 +vn -0.3611 0.4713 0.8047 +vn -0.4488 -0.3147 0.8364 +vn 0.1833 -0.5864 0.7890 +vn 0.4488 -0.3147 0.8364 +vn -0.0000 0.1578 0.9875 +vn 0.7752 0.0387 0.6306 +vn -0.7752 0.0387 0.6306 +vn -0.6507 0.1488 0.7447 +vn 0.6507 0.1488 0.7447 +vn 0.9278 0.3530 0.1209 +vn -0.9278 0.3530 0.1209 +vn 0.9306 0.3435 0.1263 +vn -0.9306 0.3435 0.1263 +vn -0.1369 -0.5273 0.8386 +vn 0.1369 -0.5273 0.8386 +vn -0.0000 -0.9619 0.2732 +vn -0.6351 0.0428 0.7712 +vn 0.6351 0.0428 0.7712 +vn -0.4141 0.5798 0.7016 +vn 0.4141 0.5798 0.7016 +vn -0.0000 -0.3465 0.9380 +vn -0.0000 0.5588 0.8293 +vn -0.0000 0.5334 0.8459 +vn 0.2959 0.4750 0.8288 +vn -0.6738 0.1155 0.7299 +vn -0.2959 0.4750 0.8288 +vn 0.6738 0.1155 0.7299 +vn -0.5177 -0.7041 0.4860 +vn 0.5177 -0.7041 0.4860 +vn -0.0000 -0.6989 0.7152 +vn -0.0101 -0.0700 0.9975 +vn 0.1581 -0.0843 0.9838 +vn 0.0101 -0.0700 0.9975 +vn -0.1581 -0.0843 0.9838 +vn 0.2934 -0.0602 0.9541 +vn -0.2934 -0.0602 0.9541 +vn 0.1588 -0.1065 0.9816 +vn -0.1588 -0.1065 0.9816 +vn 0.0317 -0.2198 0.9750 +vn 0.1845 -0.1863 0.9650 +vn -0.0317 -0.2198 0.9750 +vn -0.1845 -0.1863 0.9650 +vn 0.2990 -0.0356 0.9536 +vn -0.2990 -0.0356 0.9536 +vn 0.2943 -0.1020 0.9502 +vn -0.2943 -0.1020 0.9502 +vn 0.1776 -0.0608 0.9822 +vn -0.1776 -0.0608 0.9822 +vn -0.2944 0.0046 0.9557 +vn 0.2944 0.0046 0.9557 +vn -0.0887 -0.1272 0.9879 +vn 0.2036 0.1032 0.9736 +vn 0.0887 -0.1272 0.9879 +vn -0.2036 0.1032 0.9736 +vn 0.1435 0.0966 0.9849 +vn -0.1435 0.0966 0.9849 +vn 0.2886 -0.2786 0.9160 +vn -0.2886 -0.2786 0.9160 +vn -0.4508 -0.4658 0.7614 +vn 0.1133 -0.3142 0.9426 +vn -0.1133 -0.3142 0.9426 +vn -0.2741 -0.8556 0.4391 +vn 0.2741 -0.8556 0.4391 +vn -0.1423 -0.5826 0.8002 +vn 0.1423 -0.5826 0.8002 +vn -0.4229 -0.1078 0.8997 +vn 0.4229 -0.1078 0.8997 +vn -0.1921 0.1914 0.9625 +vn 0.1921 0.1914 0.9625 +vn -0.1653 0.6098 0.7751 +vn 0.1653 0.6098 0.7751 +vn 0.1431 0.5587 0.8169 +vn -0.1431 0.5587 0.8169 +vn 0.4323 0.5833 0.6877 +vn -0.4323 0.5833 0.6877 +vn 0.6881 0.2985 0.6614 +vn -0.6881 0.2985 0.6614 +vn 0.7894 -0.2032 0.5793 +vn 0.4508 -0.4658 0.7614 +vn -0.7894 -0.2032 0.5793 +vn 0.8016 0.0110 0.5977 +vn -0.8016 0.0110 0.5977 +vn -0.4603 0.8619 0.2127 +vn -0.0000 0.8592 0.5116 +vn 0.4603 0.8619 0.2127 +vn -0.4792 0.5120 -0.7129 +vn 0.4792 0.5120 -0.7129 +vn -0.2313 0.9570 0.1751 +vn -0.1217 0.6503 -0.7499 +vn 0.1217 0.6503 -0.7499 +vn -0.2275 0.8745 -0.4283 +vn 0.2275 0.8745 -0.4283 +vn -0.3456 0.9125 -0.2192 +vn 0.6957 0.5814 -0.4218 +vn 0.3456 0.9125 -0.2192 +vn -0.6957 0.5814 -0.4218 +vn -0.9070 -0.4009 -0.1290 +vn -0.9302 -0.3062 -0.2024 +vn 0.5444 -0.8372 -0.0533 +vn 0.9302 -0.3062 -0.2024 +vn -0.5444 -0.8372 -0.0533 +vn 0.4720 -0.8637 -0.1768 +vn -0.4720 -0.8637 -0.1768 +vn -0.0000 -0.7711 -0.6367 +vn 0.2771 -0.3147 -0.9078 +vn -0.0000 -0.2133 -0.9770 +vn -0.2771 -0.3147 -0.9078 +vn -0.6894 -0.6687 -0.2786 +vn 0.1514 -0.1510 -0.9769 +vn -0.0000 -0.2974 -0.9548 +vn -0.1514 -0.1510 -0.9769 +vn 0.0675 -0.7832 -0.6181 +vn -0.0000 -0.8818 -0.4716 +vn -0.0675 -0.7832 -0.6181 +vn 0.5551 -0.4762 -0.6820 +vn -0.5551 -0.4762 -0.6820 +vn 0.6204 0.0835 -0.7798 +vn -0.6204 0.0835 -0.7798 +vn 0.7799 -0.0105 -0.6259 +vn -0.7799 -0.0105 -0.6259 +vn 0.6894 -0.6687 -0.2786 +vn 0.8957 0.2578 -0.3624 +vn -0.8957 0.2578 -0.3624 +vn 0.9787 -0.1959 0.0615 +vn -0.9787 -0.1959 0.0615 +vn -0.8872 -0.1577 0.4336 +vn 0.7857 -0.5715 0.2368 +vn -0.7857 -0.5715 0.2368 +vn -0.3489 -0.9371 -0.0082 +vn 0.4455 -0.3584 -0.8204 +vn -0.0000 -0.6913 -0.7226 +vn -0.0000 -0.3049 -0.9524 +vn -0.4455 -0.3584 -0.8204 +vn -0.5223 -0.6536 -0.5477 +vn 0.5223 -0.6536 -0.5477 +vn -0.0000 -0.9417 -0.3365 +vn -0.5071 -0.8376 -0.2033 +vn 0.5727 -0.8197 0.0120 +vn -0.0000 -0.9831 -0.1833 +vn -0.5727 -0.8197 0.0120 +vn 0.7211 -0.6898 0.0651 +vn 0.9850 -0.1605 0.0631 +vn -0.7211 -0.6898 0.0651 +vn -0.9850 -0.1605 0.0631 +vn 0.4730 0.1763 -0.8632 +vn -0.0000 0.3650 -0.9310 +vn -0.4730 0.1763 -0.8632 +vn 0.4442 0.7244 0.5271 +vn -0.0000 0.9997 0.0226 +vn -0.0000 0.8306 0.5568 +vn -0.4442 0.7244 0.5271 +vn -0.4135 0.9096 0.0395 +vn 0.3913 0.8153 -0.4268 +vn -0.0000 0.8343 -0.5514 +vn -0.3913 0.8153 -0.4268 +vn 0.7717 0.6311 0.0785 +vn 0.4444 0.7886 0.4250 +vn -0.7717 0.6311 0.0785 +vn -0.4444 0.7886 0.4250 +vn 0.7418 0.5164 0.4279 +vn 0.6682 0.6719 0.3195 +vn -0.7418 0.5164 0.4279 +vn -0.6682 0.6719 0.3195 +vn 0.8486 0.5288 -0.0140 +vn 0.6784 0.7314 -0.0695 +vn -0.8486 0.5288 -0.0140 +vn -0.6784 0.7314 -0.0695 +vn 0.8722 0.3146 -0.3747 +vn 0.6075 0.5696 -0.5536 +vn -0.8722 0.3146 -0.3747 +vn -0.6075 0.5696 -0.5536 +vn 0.6197 -0.0605 -0.7825 +vn 0.6708 -0.0453 -0.7403 +vn -0.6197 -0.0605 -0.7825 +vn 0.4135 0.9096 0.0395 +vn 0.3406 0.8832 0.3223 +vn -0.3406 0.8832 0.3223 +vn -0.0000 0.5293 0.8485 +vn 0.9983 -0.0283 -0.0502 +vn -0.9983 -0.0283 -0.0502 +vn 0.8403 0.4934 0.2246 +vn -0.8403 0.4934 0.2246 +vn 0.5071 -0.8376 -0.2033 +vn 0.5790 -0.8027 0.1427 +vn -0.5790 -0.8027 0.1427 +vn -0.5633 -0.8173 -0.1213 +vn 0.3123 -0.9500 0.0012 +vn -0.3123 -0.9500 0.0012 +vn 0.8872 -0.1577 0.4336 +vn 0.3255 -0.6029 -0.7284 +vn -0.3255 -0.6029 -0.7284 +vn -0.5292 -0.5051 -0.6817 +vn 0.5633 -0.8173 -0.1213 +vn 0.5292 -0.5051 -0.6817 +vn -0.2793 0.7683 0.5759 +vn 0.5512 -0.0788 0.8307 +vn 0.0188 0.8723 0.4887 +vn 0.2793 0.7683 0.5759 +vn -0.5512 -0.0788 0.8307 +vn -0.4493 -0.0383 0.8926 +vn 0.3215 -0.0923 0.9424 +vn 0.3836 0.8630 0.3288 +vn -0.3215 -0.0923 0.9424 +vn -0.0188 0.8723 0.4887 +vn -0.3836 0.8630 0.3288 +vn 0.7788 0.1678 0.6044 +vn -0.7788 0.1678 0.6044 +vn 0.1545 -0.1239 0.9802 +vn -0.1545 -0.1239 0.9802 +vn 0.6526 -0.4768 0.5888 +vn -0.6526 -0.4768 0.5888 +vn 0.0411 0.3108 0.9496 +vn -0.0411 0.3108 0.9496 +vn 0.5029 -0.7810 0.3703 +vn -0.5029 -0.7810 0.3703 +vn -0.5384 0.2953 0.7893 +vn 0.3300 0.3157 0.8896 +vn 0.0295 -0.6350 0.7719 +vn -0.3300 0.3157 0.8896 +vn -0.0295 -0.6350 0.7719 +vn 0.5384 0.2953 0.7893 +vn 0.1629 0.8581 0.4870 +vn -0.1629 0.8581 0.4870 +vn -0.1868 0.9538 0.2351 +vn 0.1868 0.9538 0.2351 +vn -0.9848 -0.0996 0.1426 +vn 0.9848 -0.0996 0.1426 +vn 0.7622 0.6471 -0.0193 +vn -0.1496 -0.7455 0.6495 +vn 0.1496 -0.7455 0.6495 +vn 0.5605 -0.6609 0.4991 +vn -0.5605 -0.6609 0.4991 +vn 0.6842 -0.5558 0.4722 +vn -0.6842 -0.5558 0.4722 +vn 0.8572 -0.4931 -0.1483 +vn -0.8572 -0.4931 -0.1483 +vn -0.7312 0.1144 0.6725 +vn 0.7312 0.1144 0.6725 +vn 0.4493 -0.0383 0.8926 +vn 0.5998 0.5131 0.6139 +vn -0.5998 0.5131 0.6139 +vn 0.9610 -0.1188 0.2499 +vn 0.8420 -0.1763 0.5098 +vn -0.9610 -0.1188 0.2499 +vn 0.8515 0.0414 0.5228 +vn 0.4814 0.6344 0.6048 +vn -0.8420 -0.1763 0.5098 +vn -0.8515 0.0414 0.5228 +vn -0.4814 0.6344 0.6048 +vn 0.8303 -0.4790 0.2850 +vn 0.6864 -0.6234 0.3746 +vn -0.8303 -0.4790 0.2850 +vn 0.7261 -0.4989 0.4732 +vn 0.7949 -0.2332 0.5601 +vn -0.7261 -0.4989 0.4732 +vn -0.6864 -0.6234 0.3746 +vn -0.7949 -0.2332 0.5601 +vn 0.6593 -0.4685 0.5881 +vn 0.6482 -0.4206 0.6347 +vn -0.6593 -0.4685 0.5881 +vn -0.6482 -0.4206 0.6347 +vn -0.5725 -0.4189 0.7048 +vn 0.7584 0.2665 0.5948 +vn 0.5725 -0.4189 0.7048 +vn -0.7584 0.2665 0.5948 +vn -0.4492 0.3799 0.8086 +vn 0.4492 0.3799 0.8086 +vn -0.2929 0.3709 0.8813 +vn 0.6450 0.3102 0.6984 +vn 0.2929 0.3709 0.8813 +vn -0.6450 0.3102 0.6984 +vn -0.0331 0.9449 0.3256 +vn 0.0331 0.9449 0.3256 +vn 0.4618 -0.3291 0.8237 +vn -0.4618 -0.3291 0.8237 +vn -0.2624 -0.5331 0.8043 +vn 0.2624 -0.5331 0.8043 +vn -0.7529 -0.0338 0.6573 +vn 0.7529 -0.0338 0.6573 +vn -0.5831 0.4999 0.6403 +vn -0.7622 0.6471 -0.0193 +vn 0.5831 0.4999 0.6403 +vn 0.0650 0.7039 0.7074 +vn -0.0650 0.7039 0.7074 +vn 0.1951 0.0390 0.9800 +vn -0.1951 0.0390 0.9800 +vn -0.4085 0.1273 0.9039 +vn 0.4085 0.1273 0.9039 +vn 0.3347 -0.0046 0.9423 +vn -0.3347 -0.0046 0.9423 +vn -0.4448 -0.0937 0.8907 +vn 0.3144 -0.1038 0.9436 +vn 0.3343 0.1068 0.9364 +vn -0.3144 -0.1038 0.9436 +vn -0.3343 0.1068 0.9364 +vn 0.2897 0.3158 0.9035 +vn -0.2897 0.3158 0.9035 +vn -0.3831 -0.0685 0.9211 +vn 0.3831 -0.0685 0.9211 +vn -0.0989 -0.8408 -0.5322 +vn -0.0253 -0.6796 -0.7331 +vn 0.0989 -0.8408 -0.5322 +vn 0.0253 -0.6796 -0.7331 +vn 0.6366 -0.5043 -0.5834 +vn -0.6366 -0.5043 -0.5834 +vn 0.9253 0.0918 -0.3680 +vn -0.9253 0.0918 -0.3680 +vn 0.2870 0.5978 -0.7485 +vn -0.2870 0.5978 -0.7485 +vn -0.4142 0.5509 -0.7245 +vn 0.4142 0.5509 -0.7245 +vn -0.6501 0.5847 -0.4854 +vn 0.6501 0.5847 -0.4854 +vn -0.6708 -0.0453 -0.7403 +vn -0.3679 -0.2836 0.8856 +vn 0.4448 -0.0937 0.8907 +vt 0.890955 0.590063 +vt 0.860081 0.560115 +vt 0.904571 0.559404 +vt 0.856226 0.850547 +vt 0.888398 0.821999 +vt 0.900640 0.853232 +vt 0.853018 0.521562 +vt 0.920166 0.524546 +vt 0.847458 0.888748 +vt 0.914672 0.888748 +vt 0.798481 0.569535 +vt 0.795104 0.838402 +vt 0.870622 0.589649 +vt 0.828900 0.590771 +vt 0.826436 0.818537 +vt 0.868067 0.821510 +vt 0.854402 0.604754 +vt 0.828171 0.633354 +vt 0.827598 0.775964 +vt 0.852534 0.805700 +vt 0.791018 0.645443 +vt 0.791018 0.762238 +vt 0.855181 0.668527 +vt 0.856142 0.742025 +vt 0.844839 0.707525 +vt 0.854107 0.625459 +vt 0.853157 0.785002 +vt 0.867508 0.642291 +vt 0.900375 0.666964 +vt 0.901223 0.745592 +vt 0.867293 0.768782 +vt 0.842358 0.702491 +vt 0.921180 0.713713 +vt 0.931889 0.636832 +vt 0.918898 0.699697 +vt 0.931368 0.777093 +vt 0.968213 0.770220 +vt 0.905882 0.627902 +vt 0.890474 0.641909 +vt 0.904990 0.784860 +vt 0.906232 0.605742 +vt 0.904357 0.807013 +vt 0.931250 0.820926 +vt 0.933717 0.593037 +vt 0.968392 0.645333 +vt 0.965038 0.841671 +vt 0.968392 0.573812 +vt 0.889591 0.593275 +vt 0.887178 0.818729 +vt 0.900583 0.804677 +vt 0.902359 0.607909 +vt 0.898822 0.786233 +vt 0.899781 0.626257 +vt 0.890219 0.770183 +vt 0.887351 0.775442 +vt 0.887842 0.636527 +vt 0.870376 0.775972 +vt 0.859881 0.623942 +vt 0.870908 0.635245 +vt 0.858859 0.786774 +vt 0.859664 0.608186 +vt 0.857942 0.802505 +vt 0.871664 0.593961 +vt 0.869299 0.817249 +vt 0.879400 0.616512 +vt 0.878029 0.795063 +vt 0.536419 0.062072 +vt 0.518916 0.050294 +vt 0.540260 0.053805 +vt 0.501452 0.062043 +vt 0.518925 0.059681 +vt 0.542788 0.064089 +vt 0.551930 0.058338 +vt 0.495083 0.064047 +vt 0.497626 0.053770 +vt 0.555073 0.061900 +vt 0.482805 0.061829 +vt 0.485955 0.058273 +vt 0.563812 0.076586 +vt 0.546290 0.072669 +vt 0.491565 0.072625 +vt 0.474014 0.076511 +vt 0.583135 0.108495 +vt 0.548333 0.084893 +vt 0.489507 0.084858 +vt 0.454527 0.108481 +vt 0.605512 0.165134 +vt 0.621513 0.227818 +vt 0.553118 0.209599 +vt 0.416514 0.229490 +vt 0.432024 0.165644 +vt 0.485339 0.210053 +vt 0.676379 0.233241 +vt 0.647395 0.200502 +vt 0.360308 0.235899 +vt 0.372747 0.256357 +vt 0.683908 0.279995 +vt 0.664761 0.253225 +vt 0.353696 0.284606 +vt 0.707254 0.310054 +vt 0.715342 0.265392 +vt 0.330721 0.316853 +vt 0.351187 0.317440 +vt 0.697446 0.332673 +vt 0.687515 0.311539 +vt 0.341964 0.339667 +vt 0.362723 0.329722 +vt 0.662817 0.372521 +vt 0.676824 0.323937 +vt 0.379297 0.378686 +vt 0.402772 0.362131 +vt 0.618316 0.375151 +vt 0.639050 0.357330 +vt 0.424583 0.379267 +vt 0.604826 0.397804 +vt 0.626842 0.395792 +vt 0.439252 0.401540 +vt 0.442396 0.381222 +vt 0.553095 0.390512 +vt 0.600808 0.377857 +vt 0.490934 0.391862 +vt 0.482938 0.358497 +vt 0.521923 0.386009 +vt 0.559674 0.357011 +vt 0.521086 0.343868 +vt 0.599845 0.344815 +vt 0.577279 0.340156 +vt 0.441977 0.347815 +vt 0.615546 0.342005 +vt 0.634472 0.332311 +vt 0.425972 0.345582 +vt 0.662406 0.312804 +vt 0.406362 0.336480 +vt 0.668440 0.297958 +vt 0.377061 0.317685 +vt 0.664101 0.277872 +vt 0.370304 0.302644 +vt 0.639236 0.253047 +vt 0.374100 0.281778 +vt 0.613992 0.242662 +vt 0.398938 0.255633 +vt 0.572941 0.258564 +vt 0.424464 0.244473 +vt 0.519760 0.248864 +vt 0.466409 0.259709 +vt 0.558527 0.316594 +vt 0.482619 0.317843 +vt 0.520277 0.294764 +vt 0.556923 0.291214 +vt 0.483433 0.292249 +vt 0.563905 0.272007 +vt 0.475886 0.273078 +vt 0.525483 0.068967 +vt 0.512375 0.068956 +vt 0.531231 0.073829 +vt 0.506626 0.073811 +vt 0.531019 0.087431 +vt 0.555621 0.121749 +vt 0.532669 0.090920 +vt 0.505177 0.090908 +vt 0.482177 0.121781 +vt 0.506827 0.087416 +vt 0.518981 0.151749 +vt 0.532042 0.127713 +vt 0.538112 0.158382 +vt 0.505828 0.127728 +vt 0.518941 0.128358 +vt 0.518925 0.093952 +vt 0.518927 0.085180 +vt 0.548362 0.173560 +vt 0.535214 0.166808 +vt 0.502799 0.166857 +vt 0.489683 0.173693 +vt 0.499851 0.158434 +vt 0.544281 0.193366 +vt 0.537959 0.175966 +vt 0.500100 0.176033 +vt 0.493996 0.193428 +vt 0.528757 0.191785 +vt 0.519841 0.200843 +vt 0.509219 0.191626 +vt 0.500890 0.187571 +vt 0.519132 0.185382 +vt 0.517577 0.190607 +vt 0.518998 0.159028 +vt 0.519016 0.165599 +vt 0.506910 0.171667 +vt 0.528222 0.186316 +vt 0.509787 0.186260 +vt 0.533528 0.184215 +vt 0.537248 0.187577 +vt 0.504547 0.184206 +vt 0.504604 0.176791 +vt 0.531131 0.171631 +vt 0.533449 0.176739 +vt 0.519099 0.179457 +vt 0.561572 0.167779 +vt 0.476363 0.167996 +vt 0.478371 0.149447 +vt 0.559475 0.149319 +vt 0.596138 0.133426 +vt 0.441395 0.133592 +vt 0.601169 0.147885 +vt 0.436337 0.148194 +vt 0.528933 0.084957 +vt 0.508915 0.084945 +vt 0.518925 0.083865 +vt 0.529036 0.075429 +vt 0.508820 0.075415 +vt 0.523751 0.070508 +vt 0.514106 0.070501 +vt 0.518928 0.067899 +vt 0.518929 0.069468 +vt 0.518928 0.074259 +vt 0.516297 0.074966 +vt 0.524236 0.076691 +vt 0.521560 0.074970 +vt 0.513619 0.076684 +vt 0.524601 0.079886 +vt 0.513252 0.079879 +vt 0.518926 0.079331 +vt 0.571787 0.277295 +vt 0.568351 0.292904 +vt 0.468070 0.278617 +vt 0.471978 0.294282 +vt 0.573085 0.311386 +vt 0.467790 0.313081 +vt 0.584855 0.327708 +vt 0.456477 0.329961 +vt 0.458737 0.268049 +vt 0.611720 0.255725 +vt 0.580734 0.266620 +vt 0.427062 0.257728 +vt 0.632494 0.262853 +vt 0.406068 0.265508 +vt 0.653658 0.279971 +vt 0.384904 0.283634 +vt 0.656064 0.297636 +vt 0.383015 0.301864 +vt 0.386858 0.314615 +vt 0.652752 0.310186 +vt 0.411556 0.327673 +vt 0.614408 0.331972 +vt 0.629040 0.323864 +vt 0.426727 0.335361 +vt 0.601033 0.333624 +vt 0.440344 0.336537 +vt 0.601799 0.328453 +vt 0.439372 0.331331 +vt 0.450408 0.323919 +vt 0.613335 0.327083 +vt 0.427623 0.330358 +vt 0.626851 0.320513 +vt 0.413648 0.324175 +vt 0.646248 0.306421 +vt 0.393381 0.310510 +vt 0.649541 0.296225 +vt 0.389662 0.300183 +vt 0.647785 0.283486 +vt 0.391040 0.287071 +vt 0.629829 0.267263 +vt 0.408893 0.269959 +vt 0.612641 0.261560 +vt 0.426254 0.263693 +vt 0.585166 0.270991 +vt 0.454369 0.272583 +vt 0.578124 0.281900 +vt 0.461798 0.283441 +vt 0.579548 0.309340 +vt 0.590644 0.321516 +vt 0.461204 0.311233 +vt 0.577524 0.293776 +vt 0.462754 0.295432 +vt 0.553209 0.433063 +vt 0.523031 0.433628 +vt 0.492809 0.434538 +vt 0.609819 0.431516 +vt 0.435860 0.435740 +vt 0.416915 0.400552 +vt 0.396518 0.425416 +vt 0.648174 0.419316 +vt 0.350292 0.396229 +vt 0.692106 0.388274 +vt 0.312756 0.350588 +vt 0.735879 0.312112 +vt 0.726332 0.341754 +vt 0.301067 0.320593 +vt 0.320452 0.270303 +vt 0.304876 0.261087 +vt 0.698172 0.216906 +vt 0.729900 0.256393 +vt 0.337414 0.219179 +vt 0.663103 0.190671 +vt 0.373474 0.191872 +vt 0.649444 0.022378 +vt 0.621440 0.048089 +vt 0.626908 0.015608 +vt 0.388827 0.021586 +vt 0.416419 0.047631 +vt 0.376796 0.075296 +vt 0.577206 0.032801 +vt 0.567460 0.000144 +vt 0.411318 0.015131 +vt 0.460782 0.032656 +vt 0.547413 0.041724 +vt 0.518922 0.024886 +vt 0.470636 0.000144 +vt 0.490511 0.041669 +vt 0.558059 0.053871 +vt 0.479842 0.053785 +vt 0.576951 0.057998 +vt 0.460920 0.057845 +vt 0.611687 0.078268 +vt 0.425932 0.077985 +vt 0.660451 0.076084 +vt 0.626663 0.111357 +vt 0.410618 0.111244 +vt 0.629482 0.130456 +vt 0.407648 0.130594 +vt 0.413741 0.147158 +vt 0.619303 0.159841 +vt 0.418035 0.160361 +vt 0.389677 0.201890 +vt 0.886245 0.121777 +vt 0.891780 0.036916 +vt 0.945900 0.079569 +vt 0.141314 0.112482 +vt 0.142277 0.021467 +vt 0.183115 0.092127 +vt 0.849114 0.099732 +vt 0.805584 0.010786 +vt 0.232648 0.003484 +vt 0.246353 0.076510 +vt 0.687018 0.077204 +vt 0.672384 0.022201 +vt 0.349875 0.075955 +vt 0.365979 0.020991 +vt 0.760215 0.193244 +vt 0.789046 0.233323 +vt 0.271553 0.193871 +vt 0.241255 0.236977 +vt 0.909112 0.183261 +vt 0.994525 0.167705 +vt 0.107928 0.179083 +vt 0.078961 0.060719 +vt 0.862868 0.338556 +vt 0.962901 0.344752 +vt 0.911671 0.402429 +vt 0.160557 0.356821 +vt 0.043968 0.367038 +vt 0.123776 0.315519 +vt 0.915360 0.259804 +vt 0.999856 0.254640 +vt 0.098965 0.266968 +vt 0.000144 0.259113 +vt 0.011829 0.155367 +vt 0.749542 0.334683 +vt 0.766337 0.300809 +vt 0.789162 0.313727 +vt 0.267408 0.310142 +vt 0.288183 0.346496 +vt 0.242992 0.325552 +vt 0.815314 0.276388 +vt 0.846174 0.293397 +vt 0.213065 0.285164 +vt 0.178537 0.304983 +vt 0.845007 0.256352 +vt 0.873517 0.265922 +vt 0.179662 0.263312 +vt 0.147089 0.274284 +vt 0.859075 0.228168 +vt 0.886999 0.233769 +vt 0.162803 0.231720 +vt 0.131514 0.237587 +vt 0.875030 0.184705 +vt 0.842355 0.195160 +vt 0.145224 0.182749 +vt 0.894128 0.301884 +vt 0.794286 0.364062 +vt 0.770185 0.379538 +vt 0.239776 0.382592 +vt 0.845499 0.449967 +vt 0.106400 0.432652 +vt 0.815858 0.445381 +vt 0.755700 0.418603 +vt 0.287033 0.442912 +vt 0.219260 0.477186 +vt 0.268122 0.398737 +vt 0.185281 0.484099 +vt 0.819845 0.468071 +vt 0.215894 0.503605 +vt 0.809631 0.233887 +vt 0.219168 0.237388 +vt 0.829287 0.219562 +vt 0.199067 0.222464 +vt 0.788458 0.080826 +vt 0.715482 0.139727 +vt 0.319538 0.139409 +vt 0.246666 0.114850 +vt 0.785486 0.152330 +vt 0.245969 0.151002 +vt 0.623495 0.146796 +vt 0.837382 0.156361 +vt 0.196622 0.155241 +vt 0.171653 0.132294 +vt 0.786480 0.117591 +vt 0.858171 0.137775 +vt 0.432388 0.894943 +vt 0.491058 0.881714 +vt 0.506166 0.904851 +vt 0.321637 0.893225 +vt 0.263032 0.878321 +vt 0.315867 0.868209 +vt 0.572792 0.860484 +vt 0.604825 0.879946 +vt 0.181486 0.854693 +vt 0.247207 0.901159 +vt 0.148729 0.873349 +vt 0.619962 0.791615 +vt 0.136063 0.784093 +vt 0.169745 0.787474 +vt 0.586396 0.793977 +vt 0.563786 0.739211 +vt 0.194086 0.733241 +vt 0.208656 0.740879 +vt 0.549027 0.746412 +vt 0.508270 0.697693 +vt 0.250811 0.693249 +vt 0.258399 0.707497 +vt 0.438641 0.680683 +vt 0.434803 0.658882 +vt 0.320962 0.677959 +vt 0.325318 0.656224 +vt 0.500314 0.711729 +vt 0.452955 0.700023 +vt 0.306136 0.696976 +vt 0.505666 0.730944 +vt 0.252524 0.726592 +vt 0.568148 0.787367 +vt 0.188269 0.781375 +vt 0.214575 0.750414 +vt 0.555495 0.826352 +vt 0.199850 0.820889 +vt 0.501231 0.844356 +vt 0.253846 0.840502 +vt 0.457832 0.840040 +vt 0.297562 0.837358 +vt 0.783193 0.187449 +vt 0.246955 0.187075 +vt 0.233625 0.175620 +vt 0.394766 0.686125 +vt 0.391039 0.611891 +vt 0.364838 0.684445 +vt 0.391747 0.862097 +vt 0.438797 0.870229 +vt 0.363377 0.861308 +vt 0.435018 0.718280 +vt 0.323658 0.715731 +vt 0.384658 0.710299 +vt 0.433669 0.729661 +vt 0.374400 0.708969 +vt 0.410995 0.747662 +vt 0.427812 0.742828 +vt 0.324726 0.727177 +vt 0.347028 0.745816 +vt 0.330270 0.740536 +vt 0.384657 0.795423 +vt 0.418086 0.784946 +vt 0.372270 0.794472 +vt 0.431333 0.817535 +vt 0.401605 0.841460 +vt 0.324790 0.815460 +vt 0.338952 0.783073 +vt 0.354026 0.840297 +vt 0.825107 0.209762 +vt 0.199767 0.214827 +vt 0.816266 0.203086 +vt 0.209828 0.206161 +vt 0.226485 0.183086 +vt 0.796021 0.176969 +vt 0.802192 0.184609 +vt 0.448505 0.804621 +vt 0.473386 0.824700 +vt 0.307886 0.802031 +vt 0.282357 0.821525 +vt 0.321237 0.777208 +vt 0.423718 0.754191 +vt 0.435868 0.779569 +vt 0.334089 0.752045 +vt 0.319919 0.747250 +vt 0.437950 0.749777 +vt 0.312907 0.729222 +vt 0.440995 0.724383 +vt 0.445392 0.731997 +vt 0.317510 0.721697 +vt 0.455277 0.713731 +vt 0.303460 0.710657 +vt 0.512485 0.828811 +vt 0.242975 0.824574 +vt 0.550942 0.811814 +vt 0.204839 0.806417 +vt 0.552139 0.787682 +vt 0.204331 0.782156 +vt 0.539407 0.764539 +vt 0.542850 0.755753 +vt 0.217774 0.759319 +vt 0.508439 0.743135 +vt 0.249419 0.738732 +vt 0.454776 0.761665 +vt 0.302729 0.758742 +vt 0.286960 0.745020 +vt 0.470841 0.748408 +vt 0.475403 0.783904 +vt 0.281439 0.780511 +vt 0.268291 0.766661 +vt 0.503673 0.787562 +vt 0.494476 0.802470 +vt 0.252972 0.783410 +vt 0.261790 0.798626 +vt 0.516802 0.807339 +vt 0.239243 0.802891 +vt 0.237920 0.787045 +vt 0.518562 0.791602 +vt 0.484068 0.628776 +vt 0.543385 0.683538 +vt 0.276936 0.625067 +vt 0.216123 0.678120 +vt 0.581052 0.726933 +vt 0.177176 0.720426 +vt 0.616701 0.759965 +vt 0.140379 0.752377 +vt 0.660647 0.741167 +vt 0.707492 0.759884 +vt 0.097038 0.732052 +vt 0.677256 0.670436 +vt 0.745511 0.652100 +vt 0.049526 0.748824 +vt 0.083564 0.662038 +vt 0.671403 0.592656 +vt 0.740843 0.572428 +vt 0.019409 0.639749 +vt 0.092820 0.589862 +vt 0.834705 0.206959 +vt 0.051216 0.522659 +vt 0.033664 0.564403 +vt 0.620420 0.565675 +vt 0.498072 0.552315 +vt 0.145041 0.562595 +vt 0.264218 0.550140 +vt 0.369913 0.610196 +vt 0.464579 0.342230 +vt 0.176788 0.196179 +vt 0.770572 0.444261 +vt 0.271364 0.473316 +vt 0.488870 0.770464 +vt 0.834578 0.206879 +s 1 +f 47/1/1 3/2/2 45/3/3 +f 4/4/4 48/5/5 46/6/6 +f 45/3/3 5/7/7 43/8/8 +f 6/9/9 46/6/6 44/10/10 +f 3/2/2 7/11/11 5/7/7 +f 8/12/12 4/4/4 6/9/9 +f 1/13/13 9/14/14 3/2/2 +f 10/15/15 2/16/16 4/4/4 +f 11/17/17 15/18/18 9/14/14 +f 16/19/19 12/20/20 10/15/15 +f 9/14/14 17/21/21 7/11/11 +f 18/22/22 10/15/15 8/12/12 +f 21/23/23 17/21/21 15/18/18 +f 22/24/24 18/22/22 20/25/25 +f 13/26/26 21/23/23 15/18/18 +f 22/24/24 14/27/27 16/19/19 +f 23/28/28 27/29/29 21/23/23 +f 28/30/30 24/31/31 22/24/24 +f 27/29/29 19/32/32 21/23/23 +f 28/30/30 20/25/25 30/33/33 +f 33/34/34 29/35/35 27/29/29 +f 34/36/36 30/33/33 32/37/37 +f 35/38/38 27/29/29 25/39/39 +f 36/40/40 28/30/30 34/36/36 +f 37/41/41 33/34/34 35/38/38 +f 38/42/42 34/36/36 40/43/43 +f 39/44/44 31/45/45 33/34/34 +f 40/43/43 32/37/37 42/46/46 +f 45/3/3 41/47/47 39/44/44 +f 46/6/6 42/46/46 44/10/10 +f 47/1/1 39/44/44 37/41/41 +f 48/5/5 40/43/43 46/6/6 +f 37/41/41 49/48/48 47/1/1 +f 38/42/42 50/49/49 52/50/50 +f 35/38/38 51/51/51 37/41/41 +f 36/40/40 52/50/50 54/52/52 +f 25/39/39 53/53/53 35/38/38 +f 26/54/54 54/52/52 56/55/55 +f 23/28/28 55/56/56 25/39/39 +f 24/31/31 56/55/55 58/57/57 +f 23/28/28 59/58/58 57/59/59 +f 60/60/60 24/31/31 58/57/57 +f 13/26/26 63/61/61 59/58/58 +f 64/62/62 14/27/27 60/60/60 +f 11/17/17 65/63/63 63/61/61 +f 66/64/64 12/20/20 64/62/62 +f 1/13/13 49/48/48 65/63/63 +f 50/49/49 2/16/16 66/64/64 +f 61/65/65 65/63/63 49/48/48 +f 50/49/49 66/64/64 62/66/66 +f 63/61/61 65/63/63 61/65/65 +f 62/66/66 66/64/64 64/62/62 +f 61/65/65 59/58/58 63/61/61 +f 64/62/62 60/60/60 62/66/66 +f 61/65/65 57/59/59 59/58/58 +f 60/60/60 58/57/57 62/66/66 +f 61/65/65 55/56/56 57/59/59 +f 58/57/57 56/55/55 62/66/66 +f 61/65/65 53/53/53 55/56/56 +f 56/55/55 54/52/52 62/66/66 +f 61/65/65 51/51/51 53/53/53 +f 54/52/52 52/50/50 62/66/66 +f 61/65/65 49/48/48 51/51/51 +f 52/50/50 50/49/49 62/66/66 +f 174/67/67 91/68/68 89/69/69 +f 175/70/70 91/68/68 176/71/71 +f 172/72/72 89/69/69 87/73/73 +f 173/74/74 90/75/75 175/70/70 +f 85/76/76 172/72/72 87/73/73 +f 173/74/74 86/77/77 88/78/78 +f 83/79/79 170/80/80 85/76/76 +f 171/81/81 84/82/82 86/77/77 +f 81/83/83 168/84/84 83/79/79 +f 169/85/85 82/86/86 84/82/82 +f 79/87/87 146/88/88 164/89/89 +f 147/90/90 80/91/91 165/92/92 +f 94/93/93 146/88/88 92/94/94 +f 95/95/95 147/90/90 149/96/96 +f 94/93/93 150/97/97 148/98/98 +f 151/99/99 95/95/95 149/96/96 +f 98/100/100 150/97/97 96/101/101 +f 99/102/102 151/99/99 153/103/103 +f 100/104/104 152/105/105 98/100/100 +f 101/106/106 153/103/103 155/107/107 +f 102/108/108 154/109/109 100/104/104 +f 103/110/110 155/107/107 157/111/111 +f 102/108/108 158/112/112 156/113/113 +f 159/114/114 103/110/110 157/111/111 +f 106/115/115 158/112/112 104/116/116 +f 107/117/117 159/114/114 161/118/118 +f 108/119/119 160/120/120 106/115/115 +f 109/121/121 161/118/118 163/122/122 +f 67/123/123 162/124/124 108/119/119 +f 67/123/123 163/122/122 68/125/125 +f 128/126/126 162/124/124 110/127/127 +f 129/128/128 163/122/122 161/118/118 +f 128/126/126 158/112/112 160/120/120 +f 159/114/114 129/128/128 161/118/118 +f 156/113/113 179/129/129 126/130/130 +f 157/111/111 180/131/131 159/114/114 +f 154/109/109 126/130/130 124/132/132 +f 155/107/107 127/133/133 157/111/111 +f 152/105/105 124/132/132 122/134/134 +f 153/103/103 125/135/135 155/107/107 +f 150/97/97 122/134/134 120/136/136 +f 151/99/99 123/137/137 153/103/103 +f 148/98/98 120/136/136 118/138/138 +f 149/96/96 121/139/139 151/99/99 +f 146/88/88 118/138/138 116/140/140 +f 147/90/90 119/141/141 149/96/96 +f 164/89/89 116/140/140 114/142/142 +f 165/92/92 117/143/143 147/90/90 +f 114/142/142 177/144/144 164/89/89 +f 177/144/144 115/145/145 165/92/92 +f 162/124/124 112/146/146 110/127/127 +f 163/122/122 113/147/147 68/125/125 +f 112/146/146 178/148/148 183/149/149 +f 178/148/148 113/147/147 184/150/150 +f 181/151/151 178/148/148 177/144/144 +f 182/152/152 178/148/148 184/150/150 +f 135/153/153 176/71/71 174/67/67 +f 176/71/71 136/154/154 175/70/70 +f 133/155/155 174/67/67 172/72/72 +f 175/70/70 134/156/156 173/74/74 +f 133/155/155 170/80/80 131/157/157 +f 134/156/156 171/81/81 173/74/74 +f 166/158/158 185/159/159 168/84/84 +f 186/160/160 167/161/161 169/85/85 +f 131/157/157 168/84/84 185/159/159 +f 169/85/85 132/162/162 186/160/160 +f 190/163/163 187/164/164 144/165/165 +f 190/163/163 188/166/166 189/167/167 +f 187/164/164 69/168/168 185/159/159 +f 188/166/166 69/168/168 189/167/167 +f 131/157/157 69/168/168 130/169/169 +f 132/162/162 69/168/168 186/160/160 +f 142/170/170 191/171/171 144/165/165 +f 192/172/172 143/173/173 145/174/174 +f 140/175/175 193/176/176 142/170/170 +f 194/177/177 141/178/178 143/173/173 +f 197/179/179 140/175/175 139/180/180 +f 198/181/181 141/178/178 196/182/182 +f 71/183/183 139/180/180 138/184/184 +f 71/183/183 139/180/180 198/181/181 +f 144/165/165 70/185/185 190/163/163 +f 145/174/174 70/185/185 192/172/172 +f 191/171/171 208/186/186 70/185/185 +f 192/172/172 208/186/186 207/187/187 +f 71/183/183 200/188/188 197/179/179 +f 201/189/189 71/183/183 198/181/181 +f 197/179/179 202/190/190 195/191/191 +f 203/192/192 198/181/181 196/182/182 +f 202/190/190 193/176/176 195/191/191 +f 203/192/192 194/177/177 205/193/193 +f 193/176/176 206/194/194 191/171/171 +f 207/187/187 194/177/177 192/172/172 +f 204/195/195 200/188/188 199/196/196 +f 205/193/193 201/189/189 203/192/192 +f 199/196/196 206/194/194 204/195/195 +f 207/187/187 199/196/196 205/193/193 +f 139/180/180 164/89/89 177/144/144 +f 165/92/92 139/180/180 177/144/144 +f 140/175/175 211/197/197 164/89/89 +f 212/198/198 141/178/178 165/92/92 +f 144/165/165 211/197/197 142/170/170 +f 145/174/174 212/198/198 214/199/199 +f 187/164/164 213/200/200 144/165/165 +f 188/166/166 214/199/199 167/161/161 +f 209/201/201 166/158/158 81/83/83 +f 210/202/202 167/161/161 214/199/199 +f 215/203/203 213/200/200 209/201/201 +f 216/204/204 214/199/199 212/198/198 +f 79/87/87 211/197/197 215/203/203 +f 212/198/198 80/91/91 216/204/204 +f 130/169/169 222/205/205 131/157/157 +f 130/169/169 223/206/206 72/207/207 +f 133/155/155 222/205/205 220/208/208 +f 223/206/206 134/156/156 221/209/209 +f 135/153/153 220/208/208 218/210/210 +f 221/209/209 136/154/154 219/211/211 +f 137/212/212 218/210/210 217/213/213 +f 219/211/211 137/212/212 217/213/213 +f 218/210/210 231/214/214 217/213/213 +f 219/211/211 231/214/214 230/215/215 +f 218/210/210 227/216/216 229/217/217 +f 228/218/218 219/211/211 230/215/215 +f 220/208/208 225/219/219 227/216/216 +f 226/220/220 221/209/209 228/218/218 +f 72/207/207 225/219/219 222/205/205 +f 72/207/207 226/220/220 224/221/221 +f 224/221/221 229/217/217 225/219/219 +f 230/215/215 224/221/221 226/220/220 +f 225/219/219 229/217/217 227/216/216 +f 228/218/218 230/215/215 226/220/220 +f 183/149/149 234/222/222 232/223/223 +f 235/224/224 184/150/150 233/225/225 +f 112/146/146 232/223/223 254/226/226 +f 233/225/225 113/147/147 255/227/227 +f 112/146/146 256/228/228 110/127/127 +f 113/147/147 257/229/229 255/227/227 +f 114/142/142 234/222/222 181/151/151 +f 115/145/145 235/224/224 253/230/230 +f 114/142/142 250/231/231 252/232/232 +f 251/233/233 115/145/145 253/230/230 +f 116/140/140 248/234/234 250/231/231 +f 249/235/235 117/143/143 251/233/233 +f 118/138/138 246/236/236 248/234/234 +f 247/237/237 119/141/141 249/235/235 +f 120/136/136 244/238/238 246/236/236 +f 245/239/239 121/139/139 247/237/237 +f 124/132/132 244/238/238 122/134/134 +f 125/135/135 245/239/239 243/240/240 +f 126/130/130 242/241/241 124/132/132 +f 127/133/133 243/240/240 241/242/242 +f 126/130/130 236/243/243 240/244/244 +f 237/245/245 127/133/133 241/242/242 +f 179/129/129 238/246/246 236/243/243 +f 239/247/247 180/131/131 237/245/245 +f 128/126/126 256/228/228 238/246/246 +f 257/229/229 129/128/128 239/247/247 +f 256/228/228 276/248/248 238/246/246 +f 257/229/229 277/249/249 259/250/250 +f 236/243/243 276/248/248 278/251/251 +f 277/249/249 237/245/245 279/252/252 +f 236/243/243 274/253/253 240/244/244 +f 237/245/245 275/254/254 279/252/252 +f 240/244/244 272/255/255 242/241/241 +f 241/242/242 273/256/256 275/254/254 +f 244/238/238 272/255/255 270/257/257 +f 273/256/256 245/239/239 271/258/258 +f 244/238/238 268/259/259 246/236/236 +f 245/239/239 269/260/260 271/258/258 +f 248/234/234 268/259/259 266/261/261 +f 269/260/260 249/235/235 267/262/262 +f 248/234/234 264/263/263 250/231/231 +f 249/235/235 265/264/264 267/262/262 +f 250/231/231 262/265/265 252/232/232 +f 251/233/233 263/266/266 265/264/264 +f 234/222/222 262/265/265 280/267/267 +f 263/266/266 235/224/224 281/268/268 +f 256/228/228 260/269/269 258/270/270 +f 261/271/271 257/229/229 259/250/250 +f 254/226/226 282/272/272 260/269/269 +f 283/273/273 255/227/227 261/271/271 +f 232/223/223 280/267/267 282/272/272 +f 281/268/268 233/225/225 283/273/273 +f 67/123/123 284/274/274 73/275/275 +f 285/276/276 67/123/123 73/275/275 +f 108/119/119 286/277/277 284/274/274 +f 287/278/278 109/121/121 285/276/276 +f 104/116/116 286/277/277 106/115/115 +f 105/279/279 287/278/278 289/280/280 +f 102/108/108 288/281/281 104/116/116 +f 103/110/110 289/280/280 291/282/282 +f 100/104/104 290/283/283 102/108/108 +f 101/106/106 291/282/282 293/284/284 +f 100/104/104 294/285/285 292/286/286 +f 295/287/287 101/106/106 293/284/284 +f 96/101/101 294/285/285 98/100/100 +f 97/288/288 295/287/287 297/289/289 +f 96/101/101 298/290/290 296/291/291 +f 299/292/292 97/288/288 297/289/289 +f 94/93/93 300/293/293 298/290/290 +f 301/294/294 95/95/95 299/292/292 +f 309/295/295 338/296/296 308/297/297 +f 309/298/295 339/299/298 329/300/299 +f 308/297/297 336/301/300 307/302/301 +f 308/303/297 337/304/302 339/299/298 +f 307/302/301 340/305/303 306/306/304 +f 307/307/301 341/308/305 337/304/302 +f 89/69/69 306/306/304 340/305/303 +f 306/306/304 90/75/75 341/308/305 +f 87/73/73 340/305/303 334/309/306 +f 341/308/305 88/78/78 335/310/307 +f 85/76/76 334/309/306 330/311/308 +f 335/310/307 86/77/77 331/312/309 +f 83/79/79 330/311/308 332/313/310 +f 331/312/309 84/82/82 333/314/311 +f 330/311/308 338/296/296 332/313/310 +f 339/299/298 331/312/309 333/314/311 +f 334/309/306 336/301/300 330/311/308 +f 335/310/307 337/304/302 341/308/305 +f 332/313/310 328/315/312 326/316/313 +f 333/314/311 329/300/299 339/299/298 +f 81/83/83 332/313/310 326/316/313 +f 333/314/311 82/86/86 327/317/314 +f 342/318/315 215/203/203 209/201/201 +f 343/319/316 216/204/204 345/320/317 +f 326/316/313 209/201/201 81/83/83 +f 327/317/314 210/202/202 343/319/316 +f 215/203/203 346/321/318 79/87/87 +f 216/204/204 347/322/319 345/320/317 +f 346/321/318 92/94/94 79/87/87 +f 347/322/319 93/323/320 301/294/294 +f 324/324/321 304/325/322 77/326/323 +f 325/327/324 304/328/322 353/329/325 +f 352/330/326 78/331/327 304/325/322 +f 353/329/325 78/332/327 351/333/328 +f 78/331/327 348/334/329 305/335/330 +f 349/336/331 78/332/327 305/337/330 +f 305/335/330 328/315/312 309/295/295 +f 329/300/299 305/337/330 309/298/295 +f 328/315/312 342/318/315 326/316/313 +f 329/300/299 343/319/316 349/336/331 +f 296/291/291 318/338/332 310/339/333 +f 319/340/334 297/289/289 311/341/335 +f 316/342/336 77/326/323 76/343/337 +f 317/344/338 77/345/323 325/327/324 +f 358/346/339 303/347/340 302/348/341 +f 359/349/342 303/350/340 357/351/343 +f 303/347/340 354/352/344 75/353/345 +f 355/354/346 303/350/340 75/355/345 +f 75/353/345 316/342/336 76/343/337 +f 317/344/338 75/355/345 76/356/337 +f 292/357/286 362/358/347 364/359/348 +f 363/360/349 293/361/284 365/362/350 +f 364/359/348 368/363/351 366/364/352 +f 369/365/353 365/362/350 367/366/354 +f 366/364/352 370/367/355 372/368/356 +f 371/369/357 367/366/354 373/370/358 +f 372/368/356 376/371/359 374/372/360 +f 377/373/361 373/370/358 375/374/362 +f 378/375/363 376/371/359 314/376/364 +f 379/377/365 377/373/361 375/374/362 +f 316/342/336 374/372/360 378/375/363 +f 375/374/362 317/344/338 379/377/365 +f 354/352/344 372/368/356 374/372/360 +f 373/370/358 355/354/346 375/374/362 +f 356/378/366 366/364/352 372/368/356 +f 367/366/354 357/351/343 373/370/358 +f 358/346/339 364/359/348 366/364/352 +f 365/362/350 359/349/342 367/366/354 +f 292/357/286 360/379/367 290/380/283 +f 293/361/284 361/381/368 365/362/350 +f 360/379/367 302/348/341 74/382/369 +f 361/381/368 302/383/341 359/349/342 +f 284/384/274 288/385/281 290/380/283 +f 289/386/280 285/387/276 291/388/282 +f 284/384/274 360/379/367 74/382/369 +f 361/381/368 285/387/276 74/389/369 +f 73/390/275 284/384/274 74/382/369 +f 74/389/369 285/387/276 73/391/275 +f 296/291/291 362/358/347 294/285/285 +f 297/289/289 363/360/349 311/341/335 +f 310/339/333 368/363/351 362/358/347 +f 369/365/353 311/341/335 363/360/349 +f 312/392/370 370/367/355 368/363/351 +f 371/369/357 313/393/371 369/365/353 +f 376/371/359 382/394/372 314/376/364 +f 377/373/361 383/395/373 371/369/357 +f 350/396/374 384/397/375 348/334/329 +f 351/333/328 385/398/376 387/399/377 +f 384/397/375 320/400/378 318/338/332 +f 385/398/376 321/401/379 387/399/377 +f 298/290/290 384/397/375 318/338/332 +f 385/398/376 299/292/292 319/340/334 +f 300/293/293 342/318/315 384/397/375 +f 343/319/316 301/294/294 385/398/376 +f 342/318/315 348/334/329 384/397/375 +f 385/398/376 349/336/331 343/319/316 +f 300/293/293 346/321/318 344/402/380 +f 345/320/317 347/322/319 301/294/294 +f 322/403/381 378/375/363 314/376/364 +f 323/404/382 379/377/365 381/405/383 +f 378/375/363 324/324/321 316/342/336 +f 379/377/365 325/327/324 381/405/383 +f 386/406/384 322/403/381 320/400/378 +f 387/399/377 323/404/382 381/405/383 +f 352/330/326 386/406/384 350/396/374 +f 353/329/325 387/399/377 381/405/383 +f 324/324/321 380/407/385 352/330/326 +f 353/329/325 381/405/383 325/327/324 +f 388/408/386 402/409/387 400/410/388 +f 389/411/389 403/412/390 415/413/391 +f 400/410/388 404/414/392 398/415/393 +f 405/416/394 401/417/395 399/418/396 +f 404/414/392 396/419/397 398/415/393 +f 405/416/394 397/420/398 407/421/399 +f 406/422/400 394/423/401 396/419/397 +f 407/421/399 395/424/402 409/425/403 +f 408/426/404 392/427/405 394/423/401 +f 409/425/403 393/428/406 411/429/407 +f 392/427/405 412/430/408 390/431/409 +f 413/432/410 393/428/406 391/433/411 +f 410/434/412 418/435/413 412/430/408 +f 419/436/414 411/429/407 413/432/410 +f 408/426/404 420/437/415 410/434/412 +f 421/438/416 409/425/403 411/429/407 +f 424/439/417 408/426/404 406/422/400 +f 425/440/418 409/425/403 423/441/419 +f 426/442/420 406/422/400 404/414/392 +f 427/443/421 407/421/399 425/440/418 +f 428/444/422 404/414/392 402/409/387 +f 429/445/423 405/416/394 427/443/421 +f 402/409/387 416/446/424 428/444/422 +f 417/447/425 403/412/390 429/445/423 +f 320/400/378 442/448/426 318/338/332 +f 321/401/379 443/449/427 445/450/428 +f 390/431/409 444/451/429 320/452/378 +f 391/433/411 445/453/428 413/432/410 +f 310/339/333 442/448/426 312/392/370 +f 443/449/427 311/341/335 313/393/371 +f 382/454/372 414/455/430 388/408/386 +f 415/413/391 383/456/373 389/411/389 +f 412/430/408 440/457/431 444/451/429 +f 441/458/432 413/432/410 445/453/428 +f 446/459/433 440/457/431 438/460/434 +f 447/461/435 441/458/432 445/453/428 +f 434/462/436 438/460/434 436/463/437 +f 439/464/438 435/465/439 437/466/440 +f 448/467/441 434/462/436 432/468/442 +f 449/469/443 435/465/439 447/461/435 +f 448/467/441 450/470/444 430/471/445 +f 449/469/443 451/472/446 433/473/447 +f 430/471/445 416/446/424 414/455/430 +f 431/474/448 417/447/425 451/472/446 +f 312/392/370 430/475/445 382/394/372 +f 431/476/448 313/393/371 383/395/373 +f 442/448/426 448/477/441 312/392/370 +f 443/449/427 449/478/443 447/479/435 +f 442/448/426 444/480/429 446/481/433 +f 447/479/435 445/450/428 443/449/427 +f 416/446/424 452/482/449 476/483/450 +f 453/484/451 417/447/425 477/485/452 +f 432/468/442 452/482/449 450/470/444 +f 433/473/447 453/484/451 463/486/453 +f 432/468/442 460/487/454 462/488/455 +f 461/489/456 433/473/447 463/486/453 +f 436/463/437 460/487/454 434/462/436 +f 437/466/440 461/489/456 459/490/457 +f 438/460/434 458/491/458 436/463/437 +f 439/464/438 459/490/457 457/492/459 +f 438/460/434 454/493/460 456/494/461 +f 455/495/462 439/464/438 457/492/459 +f 440/457/431 474/496/463 454/493/460 +f 475/497/464 441/458/432 455/495/462 +f 428/444/422 476/483/450 464/498/465 +f 477/485/452 429/445/423 465/499/466 +f 426/442/420 464/498/465 466/500/467 +f 465/499/466 427/443/421 467/501/468 +f 424/439/417 466/500/467 468/502/469 +f 467/501/468 425/440/418 469/503/470 +f 424/439/417 470/504/471 422/505/472 +f 425/440/418 471/506/473 469/503/470 +f 422/505/472 472/507/474 420/437/415 +f 423/441/419 473/508/475 471/506/473 +f 420/437/415 474/496/463 418/435/413 +f 421/438/416 475/497/464 473/508/475 +f 456/494/461 478/509/476 458/491/458 +f 457/492/459 479/510/477 481/511/478 +f 480/512/479 484/513/480 478/509/476 +f 481/511/478 485/514/481 483/515/482 +f 484/513/480 488/516/483 486/517/484 +f 489/518/485 485/514/481 487/519/486 +f 488/516/483 492/520/487 486/517/484 +f 489/518/485 493/521/488 491/522/489 +f 464/498/465 486/517/484 492/520/487 +f 487/519/486 465/499/466 493/521/488 +f 484/513/480 476/483/450 452/482/449 +f 485/514/481 477/485/452 487/519/486 +f 462/488/455 484/513/480 452/482/449 +f 463/486/453 485/514/481 479/510/477 +f 458/491/458 462/488/455 460/487/454 +f 463/486/453 459/490/457 461/489/456 +f 474/496/463 456/494/461 454/493/460 +f 475/497/464 457/492/459 481/511/478 +f 472/507/474 480/512/479 474/496/463 +f 481/511/478 473/508/475 475/497/464 +f 488/516/483 472/507/474 470/504/471 +f 489/518/485 473/508/475 483/515/482 +f 490/523/490 470/504/471 468/502/469 +f 491/522/489 471/506/473 489/518/485 +f 466/500/467 490/523/490 468/502/469 +f 491/522/489 467/501/468 469/503/470 +f 464/498/465 492/520/487 466/500/467 +f 467/501/468 493/521/488 465/499/466 +f 392/427/405 504/524/491 502/525/492 +f 505/526/493 393/428/406 503/527/494 +f 394/423/401 502/525/492 500/528/495 +f 503/527/494 395/424/402 501/529/496 +f 394/423/401 498/530/497 396/419/397 +f 395/424/402 499/531/498 501/529/496 +f 396/419/397 496/532/499 398/533/393 +f 397/420/398 497/534/500 499/531/498 +f 398/533/393 494/535/501 400/536/388 +f 399/537/396 495/538/502 497/534/500 +f 400/536/388 506/539/503 388/540/386 +f 401/541/395 507/542/504 495/538/502 +f 502/525/492 506/539/503 494/535/501 +f 503/527/494 507/542/504 505/526/493 +f 494/535/501 500/528/495 502/525/492 +f 501/529/496 495/538/502 503/527/494 +f 496/532/499 498/530/497 500/528/495 +f 501/529/496 499/531/498 497/534/500 +f 382/394/372 506/543/503 314/376/364 +f 383/544/373 507/542/504 389/545/389 +f 314/546/364 504/524/491 322/547/381 +f 505/526/493 315/548/505 323/549/382 +f 320/452/378 504/524/491 390/431/409 +f 505/526/493 321/550/379 391/433/411 +f 47/1/1 1/13/13 3/2/2 +f 4/4/4 2/16/16 48/5/5 +f 45/3/3 3/2/2 5/7/7 +f 6/9/9 4/4/4 46/6/6 +f 3/2/2 9/14/14 7/11/11 +f 8/12/12 10/15/15 4/4/4 +f 1/13/13 11/17/17 9/14/14 +f 10/15/15 12/20/20 2/16/16 +f 11/17/17 13/26/26 15/18/18 +f 16/19/19 14/27/27 12/20/20 +f 9/14/14 15/18/18 17/21/21 +f 18/22/22 16/19/19 10/15/15 +f 21/23/23 19/32/32 17/21/21 +f 22/24/24 16/19/19 18/22/22 +f 13/26/26 23/28/28 21/23/23 +f 22/24/24 24/31/31 14/27/27 +f 23/28/28 25/39/39 27/29/29 +f 28/30/30 26/54/54 24/31/31 +f 27/29/29 29/35/35 19/32/32 +f 28/30/30 22/24/24 20/25/25 +f 33/34/34 31/45/45 29/35/35 +f 34/36/36 28/30/30 30/33/33 +f 35/38/38 33/34/34 27/29/29 +f 36/40/40 26/54/54 28/30/30 +f 37/41/41 39/44/44 33/34/34 +f 38/42/42 36/40/40 34/36/36 +f 39/44/44 41/47/47 31/45/45 +f 40/43/43 34/36/36 32/37/37 +f 45/3/3 43/8/8 41/47/47 +f 46/6/6 40/43/43 42/46/46 +f 47/1/1 45/3/3 39/44/44 +f 48/5/5 38/42/42 40/43/43 +f 37/41/41 51/51/51 49/48/48 +f 38/42/42 48/5/5 50/49/49 +f 35/38/38 53/53/53 51/51/51 +f 36/40/40 38/42/42 52/50/50 +f 25/39/39 55/56/56 53/53/53 +f 26/54/54 36/40/40 54/52/52 +f 23/28/28 57/59/59 55/56/56 +f 24/31/31 26/54/54 56/55/55 +f 23/28/28 13/26/26 59/58/58 +f 60/60/60 14/27/27 24/31/31 +f 13/26/26 11/17/17 63/61/61 +f 64/62/62 12/20/20 14/27/27 +f 11/17/17 1/13/13 65/63/63 +f 66/64/64 2/16/16 12/20/20 +f 1/13/13 47/1/1 49/48/48 +f 50/49/49 48/5/5 2/16/16 +f 174/67/67 176/71/71 91/68/68 +f 175/70/70 90/75/75 91/68/68 +f 172/72/72 174/67/67 89/69/69 +f 173/74/74 88/78/78 90/75/75 +f 85/76/76 170/80/80 172/72/72 +f 173/74/74 171/81/81 86/77/77 +f 83/79/79 168/84/84 170/80/80 +f 171/81/81 169/85/85 84/82/82 +f 81/83/83 166/158/158 168/84/84 +f 169/85/85 167/161/161 82/86/86 +f 79/87/87 92/94/94 146/88/88 +f 147/90/90 93/323/320 80/91/91 +f 94/93/93 148/98/98 146/88/88 +f 95/95/95 93/323/320 147/90/90 +f 94/93/93 96/101/101 150/97/97 +f 151/99/99 97/288/288 95/95/95 +f 98/100/100 152/105/105 150/97/97 +f 99/102/102 97/288/288 151/99/99 +f 100/104/104 154/109/109 152/105/105 +f 101/106/106 99/102/102 153/103/103 +f 102/108/108 156/113/113 154/109/109 +f 103/110/110 101/106/106 155/107/107 +f 102/108/108 104/116/116 158/112/112 +f 159/114/114 105/279/279 103/110/110 +f 106/115/115 160/120/120 158/112/112 +f 107/117/117 105/279/279 159/114/114 +f 108/119/119 162/124/124 160/120/120 +f 109/121/121 107/117/117 161/118/118 +f 67/123/123 68/125/125 162/124/124 +f 67/123/123 109/121/121 163/122/122 +f 128/126/126 160/120/120 162/124/124 +f 129/128/128 111/551/506 163/122/122 +f 128/126/126 179/129/129 158/112/112 +f 159/114/114 180/131/131 129/128/128 +f 156/113/113 158/112/112 179/129/129 +f 157/111/111 127/133/133 180/131/131 +f 154/109/109 156/113/113 126/130/130 +f 155/107/107 125/135/135 127/133/133 +f 152/105/105 154/109/109 124/132/132 +f 153/103/103 123/137/137 125/135/135 +f 150/97/97 152/105/105 122/134/134 +f 151/99/99 121/139/139 123/137/137 +f 148/98/98 150/97/97 120/136/136 +f 149/96/96 119/141/141 121/139/139 +f 146/88/88 148/98/98 118/138/138 +f 147/90/90 117/143/143 119/141/141 +f 164/89/89 146/88/88 116/140/140 +f 165/92/92 115/145/145 117/143/143 +f 114/142/142 181/151/151 177/144/144 +f 177/144/144 182/152/152 115/145/145 +f 162/124/124 68/125/125 112/146/146 +f 163/122/122 111/551/506 113/147/147 +f 112/146/146 68/125/125 178/148/148 +f 178/148/148 68/125/125 113/147/147 +f 181/151/151 183/149/149 178/148/148 +f 182/152/152 177/144/144 178/148/148 +f 135/153/153 137/212/212 176/71/71 +f 176/71/71 137/212/212 136/154/154 +f 133/155/155 135/153/153 174/67/67 +f 175/70/70 136/154/154 134/156/156 +f 133/155/155 172/72/72 170/80/80 +f 134/156/156 132/162/162 171/81/81 +f 166/158/158 187/164/164 185/159/159 +f 186/160/160 188/166/166 167/161/161 +f 131/157/157 170/80/80 168/84/84 +f 169/85/85 171/81/81 132/162/162 +f 190/163/163 189/167/167 187/164/164 +f 190/163/163 145/174/174 188/166/166 +f 187/164/164 189/167/167 69/168/168 +f 188/166/166 186/160/160 69/168/168 +f 131/157/157 185/159/159 69/168/168 +f 132/162/162 130/169/169 69/168/168 +f 142/170/170 193/176/176 191/171/171 +f 192/172/172 194/177/177 143/173/173 +f 140/175/175 195/191/191 193/176/176 +f 194/177/177 196/182/182 141/178/178 +f 197/179/179 195/191/191 140/175/175 +f 198/181/181 139/180/180 141/178/178 +f 71/183/183 197/179/179 139/180/180 +f 144/165/165 191/171/171 70/185/185 +f 145/174/174 190/163/163 70/185/185 +f 191/171/171 206/194/194 208/186/186 +f 192/172/172 70/185/185 208/186/186 +f 71/183/183 199/196/196 200/188/188 +f 201/189/189 199/196/196 71/183/183 +f 197/179/179 200/188/188 202/190/190 +f 203/192/192 201/189/189 198/181/181 +f 202/190/190 204/195/195 193/176/176 +f 203/192/192 196/182/182 194/177/177 +f 193/176/176 204/195/195 206/194/194 +f 207/187/187 205/193/193 194/177/177 +f 204/195/195 202/190/190 200/188/188 +f 205/193/193 199/196/196 201/189/189 +f 199/196/196 208/186/186 206/194/194 +f 207/187/187 208/186/186 199/196/196 +f 139/180/180 140/175/175 164/89/89 +f 165/92/92 141/178/178 139/180/180 +f 140/175/175 142/170/170 211/197/197 +f 212/198/198 143/173/173 141/178/178 +f 144/165/165 213/200/200 211/197/197 +f 145/174/174 143/173/173 212/198/198 +f 187/164/164 166/158/158 213/200/200 +f 188/166/166 145/174/174 214/199/199 +f 209/201/201 213/200/200 166/158/158 +f 210/202/202 82/86/86 167/161/161 +f 215/203/203 211/197/197 213/200/200 +f 216/204/204 210/202/202 214/199/199 +f 79/87/87 164/89/89 211/197/197 +f 212/198/198 165/92/92 80/91/91 +f 130/169/169 72/207/207 222/205/205 +f 130/169/169 132/162/162 223/206/206 +f 133/155/155 131/157/157 222/205/205 +f 223/206/206 132/162/162 134/156/156 +f 135/153/153 133/155/155 220/208/208 +f 221/209/209 134/156/156 136/154/154 +f 137/212/212 135/153/153 218/210/210 +f 219/211/211 136/154/154 137/212/212 +f 218/210/210 229/217/217 231/214/214 +f 219/211/211 217/213/213 231/214/214 +f 218/210/210 220/208/208 227/216/216 +f 228/218/218 221/209/209 219/211/211 +f 220/208/208 222/205/205 225/219/219 +f 226/220/220 223/206/206 221/209/209 +f 72/207/207 224/221/221 225/219/219 +f 72/207/207 223/206/206 226/220/220 +f 224/221/221 231/214/214 229/217/217 +f 230/215/215 231/214/214 224/221/221 +f 183/149/149 181/151/151 234/222/222 +f 235/224/224 182/152/152 184/150/150 +f 112/146/146 183/149/149 232/223/223 +f 233/225/225 184/150/150 113/147/147 +f 112/146/146 254/226/226 256/228/228 +f 113/147/147 111/551/506 257/229/229 +f 114/142/142 252/232/232 234/222/222 +f 115/145/145 182/152/152 235/224/224 +f 114/142/142 116/140/140 250/231/231 +f 251/233/233 117/143/143 115/145/145 +f 116/140/140 118/138/138 248/234/234 +f 249/235/235 119/141/141 117/143/143 +f 118/138/138 120/136/136 246/236/236 +f 247/237/237 121/139/139 119/141/141 +f 120/136/136 122/134/134 244/238/238 +f 245/239/239 123/137/137 121/139/139 +f 124/132/132 242/241/241 244/238/238 +f 125/135/135 123/137/137 245/239/239 +f 126/130/130 240/244/244 242/241/241 +f 127/133/133 125/135/135 243/240/240 +f 126/130/130 179/129/129 236/243/243 +f 237/245/245 180/131/131 127/133/133 +f 179/129/129 128/126/126 238/246/246 +f 239/247/247 129/128/128 180/131/131 +f 128/126/126 110/127/127 256/228/228 +f 257/229/229 111/551/506 129/128/128 +f 256/228/228 258/270/270 276/248/248 +f 257/229/229 239/247/247 277/249/249 +f 236/243/243 238/246/246 276/248/248 +f 277/249/249 239/247/247 237/245/245 +f 236/243/243 278/251/251 274/253/253 +f 237/245/245 241/242/242 275/254/254 +f 240/244/244 274/253/253 272/255/255 +f 241/242/242 243/240/240 273/256/256 +f 244/238/238 242/241/241 272/255/255 +f 273/256/256 243/240/240 245/239/239 +f 244/238/238 270/257/257 268/259/259 +f 245/239/239 247/237/237 269/260/260 +f 248/234/234 246/236/236 268/259/259 +f 269/260/260 247/237/237 249/235/235 +f 248/234/234 266/261/261 264/263/263 +f 249/235/235 251/233/233 265/264/264 +f 250/231/231 264/263/263 262/265/265 +f 251/233/233 253/230/230 263/266/266 +f 234/222/222 252/232/232 262/265/265 +f 263/266/266 253/230/230 235/224/224 +f 256/228/228 254/226/226 260/269/269 +f 261/271/271 255/227/227 257/229/229 +f 254/226/226 232/223/223 282/272/272 +f 283/273/273 233/225/225 255/227/227 +f 232/223/223 234/222/222 280/267/267 +f 281/268/268 235/224/224 233/225/225 +f 67/123/123 108/119/119 284/274/274 +f 285/276/276 109/121/121 67/123/123 +f 108/119/119 106/115/115 286/277/277 +f 287/278/278 107/117/117 109/121/121 +f 104/116/116 288/281/281 286/277/277 +f 105/279/279 107/117/117 287/278/278 +f 102/108/108 290/283/283 288/281/281 +f 103/110/110 105/279/279 289/280/280 +f 100/104/104 292/286/286 290/283/283 +f 101/106/106 103/110/110 291/282/282 +f 100/104/104 98/100/100 294/285/285 +f 295/287/287 99/102/102 101/106/106 +f 96/101/101 296/291/291 294/285/285 +f 97/288/288 99/102/102 295/287/287 +f 96/101/101 94/93/93 298/290/290 +f 299/292/292 95/95/95 97/288/288 +f 94/93/93 92/94/94 300/293/293 +f 301/294/294 93/323/320 95/95/95 +f 309/295/295 328/315/312 338/296/296 +f 309/298/295 308/303/297 339/299/298 +f 308/297/297 338/296/296 336/301/300 +f 308/303/297 307/307/301 337/304/302 +f 307/302/301 336/301/300 340/305/303 +f 307/307/301 306/306/304 341/308/305 +f 89/69/69 91/68/68 306/306/304 +f 306/306/304 91/68/68 90/75/75 +f 87/73/73 89/69/69 340/305/303 +f 341/308/305 90/75/75 88/78/78 +f 85/76/76 87/73/73 334/309/306 +f 335/310/307 88/78/78 86/77/77 +f 83/79/79 85/76/76 330/311/308 +f 331/312/309 86/77/77 84/82/82 +f 330/311/308 336/301/300 338/296/296 +f 339/299/298 337/304/302 331/312/309 +f 334/309/306 340/305/303 336/301/300 +f 335/310/307 331/312/309 337/304/302 +f 332/313/310 338/296/296 328/315/312 +f 333/314/311 327/317/314 329/300/299 +f 81/83/83 83/79/79 332/313/310 +f 333/314/311 84/82/82 82/86/86 +f 342/318/315 344/402/380 215/203/203 +f 343/319/316 210/202/202 216/204/204 +f 326/316/313 342/318/315 209/201/201 +f 327/317/314 82/86/86 210/202/202 +f 215/203/203 344/402/380 346/321/318 +f 216/204/204 80/91/91 347/322/319 +f 346/321/318 300/293/293 92/94/94 +f 347/322/319 80/91/91 93/323/320 +f 324/324/321 352/330/326 304/325/322 +f 325/327/324 77/345/323 304/328/322 +f 352/330/326 350/396/374 78/331/327 +f 353/329/325 304/328/322 78/332/327 +f 78/331/327 350/396/374 348/334/329 +f 349/336/331 351/333/328 78/332/327 +f 305/335/330 348/334/329 328/315/312 +f 329/300/299 349/336/331 305/337/330 +f 328/315/312 348/334/329 342/318/315 +f 329/300/299 327/317/314 343/319/316 +f 296/291/291 298/290/290 318/338/332 +f 319/340/334 299/292/292 297/289/289 +f 316/342/336 324/324/321 77/326/323 +f 317/344/338 76/356/337 77/345/323 +f 358/346/339 356/378/366 303/347/340 +f 359/349/342 302/383/341 303/350/340 +f 303/347/340 356/378/366 354/352/344 +f 355/354/346 357/351/343 303/350/340 +f 75/353/345 354/352/344 316/342/336 +f 317/344/338 355/354/346 75/355/345 +f 292/357/286 294/285/285 362/358/347 +f 363/360/349 295/287/287 293/361/284 +f 364/359/348 362/358/347 368/363/351 +f 369/365/353 363/360/349 365/362/350 +f 366/364/352 368/363/351 370/367/355 +f 371/369/357 369/365/353 367/366/354 +f 372/368/356 370/367/355 376/371/359 +f 377/373/361 371/369/357 373/370/358 +f 378/375/363 374/372/360 376/371/359 +f 379/377/365 315/552/505 377/373/361 +f 316/342/336 354/352/344 374/372/360 +f 375/374/362 355/354/346 317/344/338 +f 354/352/344 356/378/366 372/368/356 +f 373/370/358 357/351/343 355/354/346 +f 356/378/366 358/346/339 366/364/352 +f 367/366/354 359/349/342 357/351/343 +f 358/346/339 360/379/367 364/359/348 +f 365/362/350 361/381/368 359/349/342 +f 292/357/286 364/359/348 360/379/367 +f 293/361/284 291/388/282 361/381/368 +f 360/379/367 358/346/339 302/348/341 +f 361/381/368 74/389/369 302/383/341 +f 284/384/274 286/553/277 288/385/281 +f 289/386/280 287/554/278 285/387/276 +f 284/384/274 290/380/283 360/379/367 +f 361/381/368 291/388/282 285/387/276 +f 296/291/291 310/339/333 362/358/347 +f 297/289/289 295/287/287 363/360/349 +f 310/339/333 312/392/370 368/363/351 +f 369/365/353 313/393/371 311/341/335 +f 312/392/370 382/394/372 370/367/355 +f 371/369/357 383/395/373 313/393/371 +f 376/371/359 370/367/355 382/394/372 +f 377/373/361 315/552/505 383/395/373 +f 350/396/374 386/406/384 384/397/375 +f 351/333/328 349/336/331 385/398/376 +f 384/397/375 386/406/384 320/400/378 +f 385/398/376 319/340/334 321/401/379 +f 298/290/290 300/293/293 384/397/375 +f 385/398/376 301/294/294 299/292/292 +f 300/293/293 344/402/380 342/318/315 +f 343/319/316 345/320/317 301/294/294 +f 322/403/381 380/407/385 378/375/363 +f 323/404/382 315/552/505 379/377/365 +f 378/375/363 380/407/385 324/324/321 +f 379/377/365 317/344/338 325/327/324 +f 386/406/384 380/407/385 322/403/381 +f 387/399/377 321/401/379 323/404/382 +f 352/330/326 380/407/385 386/406/384 +f 353/329/325 351/333/328 387/399/377 +f 388/408/386 414/455/430 402/409/387 +f 389/411/389 401/417/395 403/412/390 +f 400/410/388 402/409/387 404/414/392 +f 405/416/394 403/412/390 401/417/395 +f 404/414/392 406/422/400 396/419/397 +f 405/416/394 399/418/396 397/420/398 +f 406/422/400 408/426/404 394/423/401 +f 407/421/399 397/420/398 395/424/402 +f 408/426/404 410/434/412 392/427/405 +f 409/425/403 395/424/402 393/428/406 +f 392/427/405 410/434/412 412/430/408 +f 413/432/410 411/429/407 393/428/406 +f 410/434/412 420/437/415 418/435/413 +f 419/436/414 421/438/416 411/429/407 +f 408/426/404 422/505/472 420/437/415 +f 421/438/416 423/441/419 409/425/403 +f 424/439/417 422/505/472 408/426/404 +f 425/440/418 407/421/399 409/425/403 +f 426/442/420 424/439/417 406/422/400 +f 427/443/421 405/416/394 407/421/399 +f 428/444/422 426/442/420 404/414/392 +f 429/445/423 403/412/390 405/416/394 +f 402/409/387 414/455/430 416/446/424 +f 417/447/425 415/413/391 403/412/390 +f 320/400/378 444/480/429 442/448/426 +f 321/401/379 319/340/334 443/449/427 +f 390/431/409 412/430/408 444/451/429 +f 391/433/411 321/550/379 445/453/428 +f 310/339/333 318/338/332 442/448/426 +f 443/449/427 319/340/334 311/341/335 +f 382/454/372 430/471/445 414/455/430 +f 415/413/391 431/474/448 383/456/373 +f 412/430/408 418/435/413 440/457/431 +f 441/458/432 419/436/414 413/432/410 +f 446/459/433 444/451/429 440/457/431 +f 447/461/435 439/464/438 441/458/432 +f 434/462/436 446/459/433 438/460/434 +f 439/464/438 447/461/435 435/465/439 +f 448/467/441 446/459/433 434/462/436 +f 449/469/443 433/473/447 435/465/439 +f 448/467/441 432/468/442 450/470/444 +f 449/469/443 431/474/448 451/472/446 +f 430/471/445 450/470/444 416/446/424 +f 431/474/448 415/413/391 417/447/425 +f 312/392/370 448/477/441 430/475/445 +f 431/476/448 449/478/443 313/393/371 +f 442/448/426 446/481/433 448/477/441 +f 443/449/427 313/393/371 449/478/443 +f 416/446/424 450/470/444 452/482/449 +f 453/484/451 451/472/446 417/447/425 +f 432/468/442 462/488/455 452/482/449 +f 433/473/447 451/472/446 453/484/451 +f 432/468/442 434/462/436 460/487/454 +f 461/489/456 435/465/439 433/473/447 +f 436/463/437 458/491/458 460/487/454 +f 437/466/440 435/465/439 461/489/456 +f 438/460/434 456/494/461 458/491/458 +f 439/464/438 437/466/440 459/490/457 +f 438/460/434 440/457/431 454/493/460 +f 455/495/462 441/458/432 439/464/438 +f 440/457/431 418/435/413 474/496/463 +f 475/497/464 419/436/414 441/458/432 +f 428/444/422 416/446/424 476/483/450 +f 477/485/452 417/447/425 429/445/423 +f 426/442/420 428/444/422 464/498/465 +f 465/499/466 429/445/423 427/443/421 +f 424/439/417 426/442/420 466/500/467 +f 467/501/468 427/443/421 425/440/418 +f 424/439/417 468/502/469 470/504/471 +f 425/440/418 423/441/419 471/506/473 +f 422/505/472 470/504/471 472/507/474 +f 423/441/419 421/438/416 473/508/475 +f 420/437/415 472/507/474 474/496/463 +f 421/438/416 419/436/414 475/497/464 +f 456/494/461 480/512/479 478/509/476 +f 457/492/459 459/490/457 479/510/477 +f 480/512/479 482/555/507 484/513/480 +f 481/511/478 479/510/477 485/514/481 +f 484/513/480 482/555/507 488/516/483 +f 489/518/485 483/515/482 485/514/481 +f 488/516/483 490/523/490 492/520/487 +f 489/518/485 487/519/486 493/521/488 +f 464/498/465 476/483/450 486/517/484 +f 487/519/486 477/485/452 465/499/466 +f 484/513/480 486/517/484 476/483/450 +f 485/514/481 453/484/451 477/485/452 +f 462/488/455 478/509/476 484/513/480 +f 463/486/453 453/484/451 485/514/481 +f 458/491/458 478/509/476 462/488/455 +f 463/486/453 479/510/477 459/490/457 +f 474/496/463 480/512/479 456/494/461 +f 475/497/464 455/495/462 457/492/459 +f 472/507/474 482/555/507 480/512/479 +f 481/511/478 483/515/482 473/508/475 +f 488/516/483 482/555/507 472/507/474 +f 489/518/485 471/506/473 473/508/475 +f 490/523/490 488/516/483 470/504/471 +f 491/522/489 469/503/470 471/506/473 +f 466/500/467 492/520/487 490/523/490 +f 491/522/489 493/521/488 467/501/468 +f 392/427/405 390/431/409 504/524/491 +f 505/526/493 391/433/411 393/428/406 +f 394/423/401 392/427/405 502/525/492 +f 503/527/494 393/428/406 395/424/402 +f 394/423/401 500/528/495 498/530/497 +f 395/424/402 397/420/398 499/531/498 +f 396/419/397 498/530/497 496/532/499 +f 397/420/398 399/537/396 497/534/500 +f 398/533/393 496/532/499 494/535/501 +f 399/537/396 401/541/395 495/538/502 +f 400/536/388 494/535/501 506/539/503 +f 401/541/395 389/545/389 507/542/504 +f 502/525/492 504/524/491 506/539/503 +f 503/527/494 495/538/502 507/542/504 +f 494/535/501 496/532/499 500/528/495 +f 501/529/496 497/534/500 495/538/502 +f 382/394/372 388/556/386 506/543/503 +f 383/544/373 315/548/505 507/542/504 +f 314/546/364 506/539/503 504/524/491 +f 505/526/493 507/542/504 315/548/505 +f 320/452/378 322/547/381 504/524/491 +f 505/526/493 323/549/382 321/550/379 diff --git a/crates/bevy_mikktspace/examples/generate.rs b/crates/bevy_mikktspace/examples/cube_tangents.rs similarity index 100% rename from crates/bevy_mikktspace/examples/generate.rs rename to crates/bevy_mikktspace/examples/cube_tangents.rs diff --git a/crates/bevy_mikktspace/generator/.gitignore b/crates/bevy_mikktspace/generator/.gitignore new file mode 100644 index 0000000000000..c795b054e5ade --- /dev/null +++ b/crates/bevy_mikktspace/generator/.gitignore @@ -0,0 +1 @@ +build \ No newline at end of file diff --git a/crates/bevy_mikktspace/generator/CMakeLists.txt b/crates/bevy_mikktspace/generator/CMakeLists.txt new file mode 100644 index 0000000000000..a383fcc917fc4 --- /dev/null +++ b/crates/bevy_mikktspace/generator/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.7...3.26) + +if(${CMAKE_VERSION} VERSION_LESS 3.12) + cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) +endif() + +project( + MtGenerator VERSION 1.0 + DESCRIPTION "Mikktspace Test Data Generator" + LANGUAGES C) + +add_executable(mtg_generator src/generator.c src/mikktspace.c src/obj_loader.c) +set_property(TARGET mtg_generator PROPERTY C_STANDARD 99) + +# Because in C, math is optional! Yes, your high school teacher lied to you! +target_link_libraries(mtg_generator m) diff --git a/crates/bevy_mikktspace/generator/README.md b/crates/bevy_mikktspace/generator/README.md new file mode 100644 index 0000000000000..9641031dd2a18 --- /dev/null +++ b/crates/bevy_mikktspace/generator/README.md @@ -0,0 +1,14 @@ +# Mikktspace Test Generator + +This is a simple C test case generator, to match the Rust implementation of Mikktspace against the +original C reference implementation. + +The goal of this generator is to create a 'known correct' reference to match against. + +## Running + +Building and running requires CMake. + +```sh +./build.sh +``` diff --git a/crates/bevy_mikktspace/generator/build.sh b/crates/bevy_mikktspace/generator/build.sh new file mode 100755 index 0000000000000..962a405cbfded --- /dev/null +++ b/crates/bevy_mikktspace/generator/build.sh @@ -0,0 +1,14 @@ +#!/bin/bash +set -e + +printf "\nBuilding generator...\n" + +cmake -S . -B build +cmake --build build + +printf "\nRunning generator...\n" + +./build/mtg_generator "../data/suzanne_flat_tris.obj" "../data/suzanne_flat_tris.bin" +./build/mtg_generator "../data/suzanne_smooth_tris.obj" "../data/suzanne_smooth_tris.bin" +./build/mtg_generator "../data/cube.obj" "../data/cube.bin" +./build/mtg_generator "../data/suzanne_bad.obj" "../data/suzanne_bad.bin" diff --git a/crates/bevy_mikktspace/generator/src/generator.c b/crates/bevy_mikktspace/generator/src/generator.c new file mode 100644 index 0000000000000..fbcb6bbc98b4f --- /dev/null +++ b/crates/bevy_mikktspace/generator/src/generator.c @@ -0,0 +1,203 @@ +#include "obj_loader.h" +#include "mikktspace.h" + +#include +#include +#include + +typedef struct { + vec3_t position; + vec3_t normal; + vec2_t texture_coords; + vec3_t tangent; +} vertex_t; + +typedef struct { + vertex_t vertices[4096]; + uint32_t vertices_len; + uint32_t indices[4096]; + uint32_t indices_len; +} model_data_t; + +static size_t find_vertex(vertex_t *list, size_t len, vertex_t vertex) { + for (size_t i = 0; i < len; i++) { + if (vec3_eq(list[i].position, vertex.position) && + vec3_eq(list[i].normal, vertex.normal) && + vec2_eq(list[i].texture_coords, vertex.texture_coords) + ) { + return i; + } + } + + return SIZE_MAX; +} + +static void interleave_obj_to_model(mtg_obj_data_t *data, model_data_t *model) { + printf("\nInterleaving vertices...\n"); + + for (size_t i = 0; i < data->faces_len; i++) { + for (size_t v = 0; v < 3; v++) { + // Unwrap the actual data in this vertex + mtg_obj_vertex_t obj_vertex = data->faces[i].vertices[v]; + vec3_t position = data->positions[obj_vertex.position]; + vec3_t normal = data->normals[obj_vertex.normal]; + vec2_t texture_coords = data->texture_coords[obj_vertex.texture_coords]; + vertex_t vertex = {position, normal, texture_coords}; + + // Find or insert the vertex + size_t index = find_vertex(model->vertices, model->vertices_len, vertex); + if (index == SIZE_MAX) { + index = model->vertices_len; + model->vertices[index] = vertex; + model->vertices_len++; + } + + // Store the index + model->indices[(i * 3) + v] = index; + } + } + + printf("Unique vertices: %u\n", model->vertices_len); +} + +int mtg_get_num_faces(const SMikkTSpaceContext *context) { + model_data_t *data = context->m_pUserData; + return data->indices_len / 3; +} + +int mtg_get_num_vertices_of_face(const SMikkTSpaceContext *context, const int face) { + return 3; +} + +void mtg_get_position( + const SMikkTSpaceContext *context, + float pos_out[], + const int face, + const int vert +) { + model_data_t *data = context->m_pUserData; + + uint32_t index = data->indices[face * 3 + vert]; + vertex_t vertex = data->vertices[index]; + + pos_out[0] = vertex.position.x; + pos_out[1] = vertex.position.y; + pos_out[2] = vertex.position.z; +} + +void mtg_get_normal( + const SMikkTSpaceContext *context, + float norm_out[], + const int face, + const int vert +) { + model_data_t *data = context->m_pUserData; + + uint32_t index = data->indices[face * 3 + vert]; + vertex_t vertex = data->vertices[index]; + + norm_out[0] = vertex.normal.x; + norm_out[1] = vertex.normal.y; + norm_out[2] = vertex.normal.z; +} + +void mtg_get_tex_coord( + const SMikkTSpaceContext *context, + float texc_out[], + const int face, + const int vert +) { + model_data_t *data = context->m_pUserData; + + uint32_t index = data->indices[face * 3 + vert]; + vertex_t vertex = data->vertices[index]; + + texc_out[0] = vertex.texture_coords.x; + texc_out[1] = vertex.texture_coords.y; +} + +void mtg_set_tspace_basic( + const SMikkTSpaceContext *context, + const float tangent[], + const float sign, + const int face, + const int vert +) { + model_data_t *data = context->m_pUserData; + + uint32_t index = data->indices[face * 3 + vert]; + vertex_t *vertex = &data->vertices[index]; + + vertex->tangent.x = tangent[0]; + vertex->tangent.y = tangent[1]; + vertex->tangent.z = tangent[2]; +} + +int main(int argc, char *argv[]) { + // Sanity check system assumption + assert(sizeof(vertex_t) == 4 * 11); + assert(sizeof(size_t) == 8); + + if (argc != 3) { + printf("Error: Generator must receive source and target file paths\n"); + return EXIT_FAILURE; + } + char *source_path = argv[1]; + char *target_path = argv[2]; + printf("Source: %s\n", source_path); + printf("Target: %s\n", target_path); + + // Open the source data file + printf("\nLoading source file...\n"); + FILE* file = fopen(source_path, "r"); + + mtg_obj_data_t obj_data = {}; + + // OBJ files contain data line-by-line + char buffer[256]; + while (fgets(buffer, sizeof buffer, file) != NULL) { + mtg_obj_parse_line(buffer, &obj_data); + } + fclose(file); + + // Print information about the parsed OBJ + printf("Vertex Positions: %u\n", obj_data.positions_len); + printf("Vertex Normals: %u\n", obj_data.normals_len); + printf("Vertex Texture Coords: %u\n", obj_data.texture_coords_len); + printf("Faces: %u\n", obj_data.faces_len); + + // Generate interleaved vertices, we need those for modern graphics (and mikktspace) + model_data_t model_data = {}; + model_data.indices_len = obj_data.faces_len * 3; + assert(model_data.indices_len <= 4096); + interleave_obj_to_model(&obj_data, &model_data); + + // Generate tangents + printf("\nRunning MikkTSpace...\n"); + SMikkTSpaceInterface interface = { + mtg_get_num_faces, + mtg_get_num_vertices_of_face, + mtg_get_position, + mtg_get_normal, + mtg_get_tex_coord, + mtg_set_tspace_basic + }; + SMikkTSpaceContext context = { &interface, &model_data }; + genTangSpaceDefault(&context); + + // Dump to target file + printf("\nWriting results to target file...\n"); + FILE *file_out = fopen(target_path, "wb"); + + // Vertices + fwrite(&model_data.vertices_len, 4, 1, file_out); + fwrite(model_data.vertices, sizeof(vertex_t), model_data.vertices_len, file_out); + + // Indices + fwrite(&model_data.indices_len, 4, 1, file_out); + fwrite(model_data.indices, 4, model_data.indices_len, file_out); + + fclose(file_out); + + return EXIT_SUCCESS; +} diff --git a/crates/bevy_mikktspace/generator/src/mikktspace.c b/crates/bevy_mikktspace/generator/src/mikktspace.c new file mode 100644 index 0000000000000..0342ae0146f1e --- /dev/null +++ b/crates/bevy_mikktspace/generator/src/mikktspace.c @@ -0,0 +1,1899 @@ +/** \file mikktspace/mikktspace.c + * \ingroup mikktspace + */ +/** + * Copyright (C) 2011 by Morten S. Mikkelsen + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#include +#include +#include +#include +#include +#include + +#include "mikktspace.h" + +#define TFALSE 0 +#define TTRUE 1 + +#ifndef M_PI +#define M_PI 3.1415926535897932384626433832795 +#endif + +#define INTERNAL_RND_SORT_SEED 39871946 + +// internal structure +typedef struct { + float x, y, z; +} SVec3; + +static tbool veq( const SVec3 v1, const SVec3 v2 ) +{ + return (v1.x == v2.x) && (v1.y == v2.y) && (v1.z == v2.z); +} + +static SVec3 vadd( const SVec3 v1, const SVec3 v2 ) +{ + SVec3 vRes; + + vRes.x = v1.x + v2.x; + vRes.y = v1.y + v2.y; + vRes.z = v1.z + v2.z; + + return vRes; +} + + +static SVec3 vsub( const SVec3 v1, const SVec3 v2 ) +{ + SVec3 vRes; + + vRes.x = v1.x - v2.x; + vRes.y = v1.y - v2.y; + vRes.z = v1.z - v2.z; + + return vRes; +} + +static SVec3 vscale(const float fS, const SVec3 v) +{ + SVec3 vRes; + + vRes.x = fS * v.x; + vRes.y = fS * v.y; + vRes.z = fS * v.z; + + return vRes; +} + +static float LengthSquared( const SVec3 v ) +{ + return v.x*v.x + v.y*v.y + v.z*v.z; +} + +static float Length( const SVec3 v ) +{ + return sqrtf(LengthSquared(v)); +} + +static SVec3 Normalize( const SVec3 v ) +{ + return vscale(1 / Length(v), v); +} + +static float vdot( const SVec3 v1, const SVec3 v2) +{ + return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z; +} + + +static tbool NotZero(const float fX) +{ + // could possibly use FLT_EPSILON instead + return fabsf(fX) > FLT_MIN; +} + +static tbool VNotZero(const SVec3 v) +{ + // might change this to an epsilon based test + return NotZero(v.x) || NotZero(v.y) || NotZero(v.z); +} + + + +typedef struct { + int iNrFaces; + int * pTriMembers; +} SSubGroup; + +typedef struct { + int iNrFaces; + int * pFaceIndices; + int iVertexRepresentitive; + tbool bOrientPreservering; +} SGroup; + +// +#define MARK_DEGENERATE 1 +#define QUAD_ONE_DEGEN_TRI 2 +#define GROUP_WITH_ANY 4 +#define ORIENT_PRESERVING 8 + + + +typedef struct { + int FaceNeighbors[3]; + SGroup * AssignedGroup[3]; + + // normalized first order face derivatives + SVec3 vOs, vOt; + float fMagS, fMagT; // original magnitudes + + // determines if the current and the next triangle are a quad. + int iOrgFaceNumber; + int iFlag, iTSpacesOffs; + unsigned char vert_num[4]; +} STriInfo; + +typedef struct { + SVec3 vOs; + float fMagS; + SVec3 vOt; + float fMagT; + int iCounter; // this is to average back into quads. + tbool bOrient; +} STSpace; + +static int GenerateInitialVerticesIndexList(STriInfo pTriInfos[], int piTriList_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn); +static void GenerateSharedVerticesIndexList(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn); +static void InitTriInfo(STriInfo pTriInfos[], const int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn); +static int Build4RuleGroups(STriInfo pTriInfos[], SGroup pGroups[], int piGroupTrianglesBuffer[], const int piTriListIn[], const int iNrTrianglesIn); +static tbool GenerateTSpaces(STSpace psTspace[], const STriInfo pTriInfos[], const SGroup pGroups[], + const int iNrActiveGroups, const int piTriListIn[], const float fThresCos, + const SMikkTSpaceContext * pContext); + +static int MakeIndex(const int iFace, const int iVert) +{ + assert(iVert>=0 && iVert<4 && iFace>=0); + return (iFace<<2) | (iVert&0x3); +} + +static void IndexToData(int * piFace, int * piVert, const int iIndexIn) +{ + piVert[0] = iIndexIn&0x3; + piFace[0] = iIndexIn>>2; +} + +static STSpace AvgTSpace(const STSpace * pTS0, const STSpace * pTS1) +{ + STSpace ts_res; + + // this if is important. Due to floating point precision + // averaging when ts0==ts1 will cause a slight difference + // which results in tangent space splits later on + if (pTS0->fMagS==pTS1->fMagS && pTS0->fMagT==pTS1->fMagT && + veq(pTS0->vOs,pTS1->vOs) && veq(pTS0->vOt, pTS1->vOt)) + { + ts_res.fMagS = pTS0->fMagS; + ts_res.fMagT = pTS0->fMagT; + ts_res.vOs = pTS0->vOs; + ts_res.vOt = pTS0->vOt; + } + else + { + ts_res.fMagS = 0.5f*(pTS0->fMagS+pTS1->fMagS); + ts_res.fMagT = 0.5f*(pTS0->fMagT+pTS1->fMagT); + ts_res.vOs = vadd(pTS0->vOs,pTS1->vOs); + ts_res.vOt = vadd(pTS0->vOt,pTS1->vOt); + if ( VNotZero(ts_res.vOs) ) ts_res.vOs = Normalize(ts_res.vOs); + if ( VNotZero(ts_res.vOt) ) ts_res.vOt = Normalize(ts_res.vOt); + } + + return ts_res; +} + + + +static SVec3 GetPosition(const SMikkTSpaceContext * pContext, const int index); +static SVec3 GetNormal(const SMikkTSpaceContext * pContext, const int index); +static SVec3 GetTexCoord(const SMikkTSpaceContext * pContext, const int index); + + +// degen triangles +static void DegenPrologue(STriInfo pTriInfos[], int piTriList_out[], const int iNrTrianglesIn, const int iTotTris); +static void DegenEpilogue(STSpace psTspace[], STriInfo pTriInfos[], int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn, const int iTotTris); + + +tbool genTangSpaceDefault(const SMikkTSpaceContext * pContext) +{ + return genTangSpace(pContext, 180.0f); +} + +tbool genTangSpace(const SMikkTSpaceContext * pContext, const float fAngularThreshold) +{ + // count nr_triangles + int * piTriListIn = NULL, * piGroupTrianglesBuffer = NULL; + STriInfo * pTriInfos = NULL; + SGroup * pGroups = NULL; + STSpace * psTspace = NULL; + int iNrTrianglesIn = 0, f=0, t=0, i=0; + int iNrTSPaces = 0, iTotTris = 0, iDegenTriangles = 0, iNrMaxGroups = 0; + int iNrActiveGroups = 0, index = 0; + const int iNrFaces = pContext->m_pInterface->m_getNumFaces(pContext); + tbool bRes = TFALSE; + const float fThresCos = (float) cos((fAngularThreshold*(float)M_PI)/180.0f); + + // verify all call-backs have been set + if ( pContext->m_pInterface->m_getNumFaces==NULL || + pContext->m_pInterface->m_getNumVerticesOfFace==NULL || + pContext->m_pInterface->m_getPosition==NULL || + pContext->m_pInterface->m_getNormal==NULL || + pContext->m_pInterface->m_getTexCoord==NULL ) + return TFALSE; + + // count triangles on supported faces + for (f=0; fm_pInterface->m_getNumVerticesOfFace(pContext, f); + if (verts==3) ++iNrTrianglesIn; + else if (verts==4) iNrTrianglesIn += 2; + } + if (iNrTrianglesIn<=0) return TFALSE; + + // allocate memory for an index list + piTriListIn = (int *) malloc(sizeof(int)*3*iNrTrianglesIn); + pTriInfos = (STriInfo *) malloc(sizeof(STriInfo)*iNrTrianglesIn); + if (piTriListIn==NULL || pTriInfos==NULL) + { + if (piTriListIn!=NULL) free(piTriListIn); + if (pTriInfos!=NULL) free(pTriInfos); + return TFALSE; + } + + // make an initial triangle --> face index list + iNrTSPaces = GenerateInitialVerticesIndexList(pTriInfos, piTriListIn, pContext, iNrTrianglesIn); + + // make a welded index list of identical positions and attributes (pos, norm, texc) + //printf("gen welded index list begin\n"); + GenerateSharedVerticesIndexList(piTriListIn, pContext, iNrTrianglesIn); + //printf("gen welded index list end\n"); + + // Mark all degenerate triangles + iTotTris = iNrTrianglesIn; + iDegenTriangles = 0; + for (t=0; tm_pInterface->m_getNumVerticesOfFace(pContext, f); + if (verts!=3 && verts!=4) continue; + + + // I've decided to let degenerate triangles and group-with-anythings + // vary between left/right hand coordinate systems at the vertices. + // All healthy triangles on the other hand are built to always be either or. + + /*// force the coordinate system orientation to be uniform for every face. + // (this is already the case for good triangles but not for + // degenerate ones and those with bGroupWithAnything==true) + bool bOrient = psTspace[index].bOrient; + if (psTspace[index].iCounter == 0) // tspace was not derived from a group + { + // look for a space created in GenerateTSpaces() by iCounter>0 + bool bNotFound = true; + int i=1; + while (i 0) bNotFound=false; + else ++i; + } + if (!bNotFound) bOrient = psTspace[index+i].bOrient; + }*/ + + // set data + for (i=0; ivOs.x, pTSpace->vOs.y, pTSpace->vOs.z}; + float bitang[] = {pTSpace->vOt.x, pTSpace->vOt.y, pTSpace->vOt.z}; + if (pContext->m_pInterface->m_setTSpace!=NULL) + pContext->m_pInterface->m_setTSpace(pContext, tang, bitang, pTSpace->fMagS, pTSpace->fMagT, pTSpace->bOrient, f, i); + if (pContext->m_pInterface->m_setTSpaceBasic!=NULL) + pContext->m_pInterface->m_setTSpaceBasic(pContext, tang, pTSpace->bOrient==TTRUE ? 1.0f : (-1.0f), f, i); + + ++index; + } + } + + free(psTspace); + + + return TTRUE; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef struct { + float vert[3]; + int index; +} STmpVert; + +static const int g_iCells = 2048; + +#ifdef _MSC_VER +# define NOINLINE __declspec(noinline) +#else +# define NOINLINE __attribute__ ((noinline)) +#endif + +// it is IMPORTANT that this function is called to evaluate the hash since +// inlining could potentially reorder instructions and generate different +// results for the same effective input value fVal. +static NOINLINE int FindGridCell(const float fMin, const float fMax, const float fVal) +{ + const float fIndex = g_iCells * ((fVal-fMin)/(fMax-fMin)); + const int iIndex = (int)fIndex; + return iIndex < g_iCells ? (iIndex >= 0 ? iIndex : 0) : (g_iCells - 1); +} + +static void MergeVertsFast(int piTriList_in_and_out[], STmpVert pTmpVert[], const SMikkTSpaceContext * pContext, const int iL_in, const int iR_in); +static void MergeVertsSlow(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int pTable[], const int iEntries); +static void GenerateSharedVerticesIndexListSlow(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn); + +static void GenerateSharedVerticesIndexList(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn) +{ + + // Generate bounding box + int * piHashTable=NULL, * piHashCount=NULL, * piHashOffsets=NULL, * piHashCount2=NULL; + STmpVert * pTmpVert = NULL; + int i=0, iChannel=0, k=0, e=0; + int iMaxCount=0; + SVec3 vMin = GetPosition(pContext, 0), vMax = vMin, vDim; + float fMin, fMax; + for (i=1; i<(iNrTrianglesIn*3); i++) + { + const int index = piTriList_in_and_out[i]; + + const SVec3 vP = GetPosition(pContext, index); + if (vMin.x > vP.x) vMin.x = vP.x; + else if (vMax.x < vP.x) vMax.x = vP.x; + if (vMin.y > vP.y) vMin.y = vP.y; + else if (vMax.y < vP.y) vMax.y = vP.y; + if (vMin.z > vP.z) vMin.z = vP.z; + else if (vMax.z < vP.z) vMax.z = vP.z; + } + + vDim = vsub(vMax,vMin); + iChannel = 0; + fMin = vMin.x; fMax=vMax.x; + if (vDim.y>vDim.x && vDim.y>vDim.z) + { + iChannel=1; + fMin = vMin.y; + fMax = vMax.y; + } + else if (vDim.z>vDim.x) + { + iChannel=2; + fMin = vMin.z; + fMax = vMax.z; + } + + // make allocations + piHashTable = (int *) malloc(sizeof(int)*iNrTrianglesIn*3); + piHashCount = (int *) malloc(sizeof(int)*g_iCells); + piHashOffsets = (int *) malloc(sizeof(int)*g_iCells); + piHashCount2 = (int *) malloc(sizeof(int)*g_iCells); + + if (piHashTable==NULL || piHashCount==NULL || piHashOffsets==NULL || piHashCount2==NULL) + { + if (piHashTable!=NULL) free(piHashTable); + if (piHashCount!=NULL) free(piHashCount); + if (piHashOffsets!=NULL) free(piHashOffsets); + if (piHashCount2!=NULL) free(piHashCount2); + GenerateSharedVerticesIndexListSlow(piTriList_in_and_out, pContext, iNrTrianglesIn); + return; + } + memset(piHashCount, 0, sizeof(int)*g_iCells); + memset(piHashCount2, 0, sizeof(int)*g_iCells); + + // count amount of elements in each cell unit + for (i=0; i<(iNrTrianglesIn*3); i++) + { + const int index = piTriList_in_and_out[i]; + const SVec3 vP = GetPosition(pContext, index); + const float fVal = iChannel==0 ? vP.x : (iChannel==1 ? vP.y : vP.z); + const int iCell = FindGridCell(fMin, fMax, fVal); + ++piHashCount[iCell]; + } + + // evaluate start index of each cell. + piHashOffsets[0]=0; + for (k=1; kpTmpVert[l].vert[c]) fvMin[c]=pTmpVert[l].vert[c]; + if (fvMax[c]dx && dy>dz) channel=1; + else if (dz>dx) channel=2; + + fSep = 0.5f*(fvMax[channel]+fvMin[channel]); + + // stop if all vertices are NaNs + if (!isfinite(fSep)) + return; + + // terminate recursion when the separation/average value + // is no longer strictly between fMin and fMax values. + if (fSep>=fvMax[channel] || fSep<=fvMin[channel]) + { + // complete the weld + for (l=iL_in; l<=iR_in; l++) + { + int i = pTmpVert[l].index; + const int index = piTriList_in_and_out[i]; + const SVec3 vP = GetPosition(pContext, index); + const SVec3 vN = GetNormal(pContext, index); + const SVec3 vT = GetTexCoord(pContext, index); + + tbool bNotFound = TTRUE; + int l2=iL_in, i2rec=-1; + while (l20); // at least 2 entries + + // separate (by fSep) all points between iL_in and iR_in in pTmpVert[] + while (iL < iR) + { + tbool bReadyLeftSwap = TFALSE, bReadyRightSwap = TFALSE; + while ((!bReadyLeftSwap) && iL=iL_in && iL<=iR_in); + bReadyLeftSwap = !(pTmpVert[iL].vert[channel]=iL_in && iR<=iR_in); + bReadyRightSwap = pTmpVert[iR].vert[channel]m_pInterface->m_getNumFaces(pContext); f++) + { + const int verts = pContext->m_pInterface->m_getNumVerticesOfFace(pContext, f); + if (verts!=3 && verts!=4) continue; + + pTriInfos[iDstTriIndex].iOrgFaceNumber = f; + pTriInfos[iDstTriIndex].iTSpacesOffs = iTSpacesOffs; + + if (verts==3) + { + unsigned char * pVerts = pTriInfos[iDstTriIndex].vert_num; + pVerts[0]=0; pVerts[1]=1; pVerts[2]=2; + piTriList_out[iDstTriIndex*3+0] = MakeIndex(f, 0); + piTriList_out[iDstTriIndex*3+1] = MakeIndex(f, 1); + piTriList_out[iDstTriIndex*3+2] = MakeIndex(f, 2); + ++iDstTriIndex; // next + } + else + { + { + pTriInfos[iDstTriIndex+1].iOrgFaceNumber = f; + pTriInfos[iDstTriIndex+1].iTSpacesOffs = iTSpacesOffs; + } + + { + // need an order independent way to evaluate + // tspace on quads. This is done by splitting + // along the shortest diagonal. + const int i0 = MakeIndex(f, 0); + const int i1 = MakeIndex(f, 1); + const int i2 = MakeIndex(f, 2); + const int i3 = MakeIndex(f, 3); + const SVec3 T0 = GetTexCoord(pContext, i0); + const SVec3 T1 = GetTexCoord(pContext, i1); + const SVec3 T2 = GetTexCoord(pContext, i2); + const SVec3 T3 = GetTexCoord(pContext, i3); + const float distSQ_02 = LengthSquared(vsub(T2,T0)); + const float distSQ_13 = LengthSquared(vsub(T3,T1)); + tbool bQuadDiagIs_02; + if (distSQ_02m_pInterface->m_getPosition(pContext, pos, iF, iI); + res.x=pos[0]; res.y=pos[1]; res.z=pos[2]; + return res; +} + +static SVec3 GetNormal(const SMikkTSpaceContext * pContext, const int index) +{ + int iF, iI; + SVec3 res; float norm[3]; + IndexToData(&iF, &iI, index); + pContext->m_pInterface->m_getNormal(pContext, norm, iF, iI); + res.x=norm[0]; res.y=norm[1]; res.z=norm[2]; + return res; +} + +static SVec3 GetTexCoord(const SMikkTSpaceContext * pContext, const int index) +{ + int iF, iI; + SVec3 res; float texc[2]; + IndexToData(&iF, &iI, index); + pContext->m_pInterface->m_getTexCoord(pContext, texc, iF, iI); + res.x=texc[0]; res.y=texc[1]; res.z=1.0f; + return res; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef union { + struct + { + int i0, i1, f; + }; + int array[3]; +} SEdge; + +static void BuildNeighborsFast(STriInfo pTriInfos[], SEdge * pEdges, const int piTriListIn[], const int iNrTrianglesIn); +static void BuildNeighborsSlow(STriInfo pTriInfos[], const int piTriListIn[], const int iNrTrianglesIn); + +// returns the texture area times 2 +static float CalcTexArea(const SMikkTSpaceContext * pContext, const int indices[]) +{ + const SVec3 t1 = GetTexCoord(pContext, indices[0]); + const SVec3 t2 = GetTexCoord(pContext, indices[1]); + const SVec3 t3 = GetTexCoord(pContext, indices[2]); + + const float t21x = t2.x-t1.x; + const float t21y = t2.y-t1.y; + const float t31x = t3.x-t1.x; + const float t31y = t3.y-t1.y; + + const float fSignedAreaSTx2 = t21x*t31y - t21y*t31x; + + return fSignedAreaSTx2<0 ? (-fSignedAreaSTx2) : fSignedAreaSTx2; +} + +static void InitTriInfo(STriInfo pTriInfos[], const int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn) +{ + int f=0, i=0, t=0; + // pTriInfos[f].iFlag is cleared in GenerateInitialVerticesIndexList() which is called before this function. + + // generate neighbor info list + for (f=0; f0 ? ORIENT_PRESERVING : 0); + + if ( NotZero(fSignedAreaSTx2) ) + { + const float fAbsArea = fabsf(fSignedAreaSTx2); + const float fLenOs = Length(vOs); + const float fLenOt = Length(vOt); + const float fS = (pTriInfos[f].iFlag&ORIENT_PRESERVING)==0 ? (-1.0f) : 1.0f; + if ( NotZero(fLenOs) ) pTriInfos[f].vOs = vscale(fS/fLenOs, vOs); + if ( NotZero(fLenOt) ) pTriInfos[f].vOt = vscale(fS/fLenOt, vOt); + + // evaluate magnitudes prior to normalization of vOs and vOt + pTriInfos[f].fMagS = fLenOs / fAbsArea; + pTriInfos[f].fMagT = fLenOt / fAbsArea; + + // if this is a good triangle + if ( NotZero(pTriInfos[f].fMagS) && NotZero(pTriInfos[f].fMagT)) + pTriInfos[f].iFlag &= (~GROUP_WITH_ANY); + } + } + + // force otherwise healthy quads to a fixed orientation + while (t<(iNrTrianglesIn-1)) + { + const int iFO_a = pTriInfos[t].iOrgFaceNumber; + const int iFO_b = pTriInfos[t+1].iOrgFaceNumber; + if (iFO_a==iFO_b) // this is a quad + { + const tbool bIsDeg_a = (pTriInfos[t].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE; + const tbool bIsDeg_b = (pTriInfos[t+1].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE; + + // bad triangles should already have been removed by + // DegenPrologue(), but just in case check bIsDeg_a and bIsDeg_a are false + if ((bIsDeg_a||bIsDeg_b)==TFALSE) + { + const tbool bOrientA = (pTriInfos[t].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; + const tbool bOrientB = (pTriInfos[t+1].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; + // if this happens the quad has extremely bad mapping!! + if (bOrientA!=bOrientB) + { + //printf("found quad with bad mapping\n"); + tbool bChooseOrientFirstTri = TFALSE; + if ((pTriInfos[t+1].iFlag&GROUP_WITH_ANY)!=0) bChooseOrientFirstTri = TTRUE; + else if ( CalcTexArea(pContext, &piTriListIn[t*3+0]) >= CalcTexArea(pContext, &piTriListIn[(t+1)*3+0]) ) + bChooseOrientFirstTri = TTRUE; + + // force match + { + const int t0 = bChooseOrientFirstTri ? t : (t+1); + const int t1 = bChooseOrientFirstTri ? (t+1) : t; + pTriInfos[t1].iFlag &= (~ORIENT_PRESERVING); // clear first + pTriInfos[t1].iFlag |= (pTriInfos[t0].iFlag&ORIENT_PRESERVING); // copy bit + } + } + } + t += 2; + } + else + ++t; + } + + // match up edge pairs + { + SEdge * pEdges = (SEdge *) malloc(sizeof(SEdge)*iNrTrianglesIn*3); + if (pEdges==NULL) + BuildNeighborsSlow(pTriInfos, piTriListIn, iNrTrianglesIn); + else + { + BuildNeighborsFast(pTriInfos, pEdges, piTriListIn, iNrTrianglesIn); + + free(pEdges); + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// + +static tbool AssignRecur(const int piTriListIn[], STriInfo psTriInfos[], const int iMyTriIndex, SGroup * pGroup); +static void AddTriToGroup(SGroup * pGroup, const int iTriIndex); + +static int Build4RuleGroups(STriInfo pTriInfos[], SGroup pGroups[], int piGroupTrianglesBuffer[], const int piTriListIn[], const int iNrTrianglesIn) +{ + const int iNrMaxGroups = iNrTrianglesIn*3; + int iNrActiveGroups = 0; + int iOffset = 0, f=0, i=0; + (void)iNrMaxGroups; /* quiet warnings in non debug mode */ + for (f=0; fiVertexRepresentitive = vert_index; + pTriInfos[f].AssignedGroup[i]->bOrientPreservering = (pTriInfos[f].iFlag&ORIENT_PRESERVING)!=0; + pTriInfos[f].AssignedGroup[i]->iNrFaces = 0; + pTriInfos[f].AssignedGroup[i]->pFaceIndices = &piGroupTrianglesBuffer[iOffset]; + ++iNrActiveGroups; + + AddTriToGroup(pTriInfos[f].AssignedGroup[i], f); + bOrPre = (pTriInfos[f].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; + neigh_indexL = pTriInfos[f].FaceNeighbors[i]; + neigh_indexR = pTriInfos[f].FaceNeighbors[i>0?(i-1):2]; + if (neigh_indexL>=0) // neighbor + { + const tbool bAnswer = + AssignRecur(piTriListIn, pTriInfos, neigh_indexL, + pTriInfos[f].AssignedGroup[i] ); + + const tbool bOrPre2 = (pTriInfos[neigh_indexL].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; + const tbool bDiff = bOrPre!=bOrPre2 ? TTRUE : TFALSE; + assert(bAnswer || bDiff); + (void)bAnswer, (void)bDiff; /* quiet warnings in non debug mode */ + } + if (neigh_indexR>=0) // neighbor + { + const tbool bAnswer = + AssignRecur(piTriListIn, pTriInfos, neigh_indexR, + pTriInfos[f].AssignedGroup[i] ); + + const tbool bOrPre2 = (pTriInfos[neigh_indexR].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; + const tbool bDiff = bOrPre!=bOrPre2 ? TTRUE : TFALSE; + assert(bAnswer || bDiff); + (void)bAnswer, (void)bDiff; /* quiet warnings in non debug mode */ + } + + // update offset + iOffset += pTriInfos[f].AssignedGroup[i]->iNrFaces; + // since the groups are disjoint a triangle can never + // belong to more than 3 groups. Subsequently something + // is completely screwed if this assertion ever hits. + assert(iOffset <= iNrMaxGroups); + } + } + } + + return iNrActiveGroups; +} + +static void AddTriToGroup(SGroup * pGroup, const int iTriIndex) +{ + pGroup->pFaceIndices[pGroup->iNrFaces] = iTriIndex; + ++pGroup->iNrFaces; +} + +static tbool AssignRecur(const int piTriListIn[], STriInfo psTriInfos[], + const int iMyTriIndex, SGroup * pGroup) +{ + STriInfo * pMyTriInfo = &psTriInfos[iMyTriIndex]; + + // track down vertex + const int iVertRep = pGroup->iVertexRepresentitive; + const int * pVerts = &piTriListIn[3*iMyTriIndex+0]; + int i=-1; + if (pVerts[0]==iVertRep) i=0; + else if (pVerts[1]==iVertRep) i=1; + else if (pVerts[2]==iVertRep) i=2; + assert(i>=0 && i<3); + + // early out + if (pMyTriInfo->AssignedGroup[i] == pGroup) return TTRUE; + else if (pMyTriInfo->AssignedGroup[i]!=NULL) return TFALSE; + if ((pMyTriInfo->iFlag&GROUP_WITH_ANY)!=0) + { + // first to group with a group-with-anything triangle + // determines it's orientation. + // This is the only existing order dependency in the code!! + if ( pMyTriInfo->AssignedGroup[0] == NULL && + pMyTriInfo->AssignedGroup[1] == NULL && + pMyTriInfo->AssignedGroup[2] == NULL ) + { + pMyTriInfo->iFlag &= (~ORIENT_PRESERVING); + pMyTriInfo->iFlag |= (pGroup->bOrientPreservering ? ORIENT_PRESERVING : 0); + } + } + { + const tbool bOrient = (pMyTriInfo->iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; + if (bOrient != pGroup->bOrientPreservering) return TFALSE; + } + + AddTriToGroup(pGroup, iMyTriIndex); + pMyTriInfo->AssignedGroup[i] = pGroup; + + { + const int neigh_indexL = pMyTriInfo->FaceNeighbors[i]; + const int neigh_indexR = pMyTriInfo->FaceNeighbors[i>0?(i-1):2]; + if (neigh_indexL>=0) + AssignRecur(piTriListIn, psTriInfos, neigh_indexL, pGroup); + if (neigh_indexR>=0) + AssignRecur(piTriListIn, psTriInfos, neigh_indexR, pGroup); + } + + + + return TTRUE; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// + +static tbool CompareSubGroups(const SSubGroup * pg1, const SSubGroup * pg2); +static void QuickSort(int* pSortBuffer, int iLeft, int iRight, unsigned int uSeed); +static STSpace EvalTspace(int face_indices[], const int iFaces, const int piTriListIn[], const STriInfo pTriInfos[], const SMikkTSpaceContext * pContext, const int iVertexRepresentitive); + +static tbool GenerateTSpaces(STSpace psTspace[], const STriInfo pTriInfos[], const SGroup pGroups[], + const int iNrActiveGroups, const int piTriListIn[], const float fThresCos, + const SMikkTSpaceContext * pContext) +{ + STSpace * pSubGroupTspace = NULL; + SSubGroup * pUniSubGroups = NULL; + int * pTmpMembers = NULL; + int iMaxNrFaces=0, iUniqueTspaces=0, g=0, i=0; + for (g=0; giNrFaces; i++) // triangles + { + const int f = pGroup->pFaceIndices[i]; // triangle number + int index=-1, iVertIndex=-1, iOF_1=-1, iMembers=0, j=0, l=0; + SSubGroup tmp_group; + tbool bFound; + SVec3 n, vOs, vOt; + if (pTriInfos[f].AssignedGroup[0]==pGroup) index=0; + else if (pTriInfos[f].AssignedGroup[1]==pGroup) index=1; + else if (pTriInfos[f].AssignedGroup[2]==pGroup) index=2; + assert(index>=0 && index<3); + + iVertIndex = piTriListIn[f*3+index]; + assert(iVertIndex==pGroup->iVertexRepresentitive); + + // is normalized already + n = GetNormal(pContext, iVertIndex); + + // project + vOs = vsub(pTriInfos[f].vOs, vscale(vdot(n,pTriInfos[f].vOs), n)); + vOt = vsub(pTriInfos[f].vOt, vscale(vdot(n,pTriInfos[f].vOt), n)); + if ( VNotZero(vOs) ) vOs = Normalize(vOs); + if ( VNotZero(vOt) ) vOt = Normalize(vOt); + + // original face number + iOF_1 = pTriInfos[f].iOrgFaceNumber; + + iMembers = 0; + for (j=0; jiNrFaces; j++) + { + const int t = pGroup->pFaceIndices[j]; // triangle number + const int iOF_2 = pTriInfos[t].iOrgFaceNumber; + + // project + SVec3 vOs2 = vsub(pTriInfos[t].vOs, vscale(vdot(n,pTriInfos[t].vOs), n)); + SVec3 vOt2 = vsub(pTriInfos[t].vOt, vscale(vdot(n,pTriInfos[t].vOt), n)); + if ( VNotZero(vOs2) ) vOs2 = Normalize(vOs2); + if ( VNotZero(vOt2) ) vOt2 = Normalize(vOt2); + + { + const tbool bAny = ( (pTriInfos[f].iFlag | pTriInfos[t].iFlag) & GROUP_WITH_ANY )!=0 ? TTRUE : TFALSE; + // make sure triangles which belong to the same quad are joined. + const tbool bSameOrgFace = iOF_1==iOF_2 ? TTRUE : TFALSE; + + const float fCosS = vdot(vOs,vOs2); + const float fCosT = vdot(vOt,vOt2); + + assert(f!=t || bSameOrgFace); // sanity check + if (bAny || bSameOrgFace || (fCosS>fThresCos && fCosT>fThresCos)) + pTmpMembers[iMembers++] = t; + } + } + + // sort pTmpMembers + tmp_group.iNrFaces = iMembers; + tmp_group.pTriMembers = pTmpMembers; + if (iMembers>1) + { + unsigned int uSeed = INTERNAL_RND_SORT_SEED; // could replace with a random seed? + QuickSort(pTmpMembers, 0, iMembers-1, uSeed); + } + + // look for an existing match + bFound = TFALSE; + l=0; + while (liVertexRepresentitive); + ++iUniqueSubGroups; + } + + // output tspace + { + const int iOffs = pTriInfos[f].iTSpacesOffs; + const int iVert = pTriInfos[f].vert_num[index]; + STSpace * pTS_out = &psTspace[iOffs+iVert]; + assert(pTS_out->iCounter<2); + assert(((pTriInfos[f].iFlag&ORIENT_PRESERVING)!=0) == pGroup->bOrientPreservering); + if (pTS_out->iCounter==1) + { + *pTS_out = AvgTSpace(pTS_out, &pSubGroupTspace[l]); + pTS_out->iCounter = 2; // update counter + pTS_out->bOrient = pGroup->bOrientPreservering; + } + else + { + assert(pTS_out->iCounter==0); + *pTS_out = pSubGroupTspace[l]; + pTS_out->iCounter = 1; // update counter + pTS_out->bOrient = pGroup->bOrientPreservering; + } + } + } + + // clean up and offset iUniqueTspaces + for (s=0; s=0 && i<3); + + // project + index = piTriListIn[3*f+i]; + n = GetNormal(pContext, index); + vOs = vsub(pTriInfos[f].vOs, vscale(vdot(n,pTriInfos[f].vOs), n)); + vOt = vsub(pTriInfos[f].vOt, vscale(vdot(n,pTriInfos[f].vOt), n)); + if ( VNotZero(vOs) ) vOs = Normalize(vOs); + if ( VNotZero(vOt) ) vOt = Normalize(vOt); + + i2 = piTriListIn[3*f + (i<2?(i+1):0)]; + i1 = piTriListIn[3*f + i]; + i0 = piTriListIn[3*f + (i>0?(i-1):2)]; + + p0 = GetPosition(pContext, i0); + p1 = GetPosition(pContext, i1); + p2 = GetPosition(pContext, i2); + v1 = vsub(p0,p1); + v2 = vsub(p2,p1); + + // project + v1 = vsub(v1, vscale(vdot(n,v1),n)); if ( VNotZero(v1) ) v1 = Normalize(v1); + v2 = vsub(v2, vscale(vdot(n,v2),n)); if ( VNotZero(v2) ) v2 = Normalize(v2); + + // weight contribution by the angle + // between the two edge vectors + fCos = vdot(v1,v2); fCos=fCos>1?1:(fCos<(-1) ? (-1) : fCos); + fAngle = (float) acos(fCos); + fMagS = pTriInfos[f].fMagS; + fMagT = pTriInfos[f].fMagT; + + res.vOs=vadd(res.vOs, vscale(fAngle,vOs)); + res.vOt=vadd(res.vOt,vscale(fAngle,vOt)); + res.fMagS+=(fAngle*fMagS); + res.fMagT+=(fAngle*fMagT); + fAngleSum += fAngle; + } + } + + // normalize + if ( VNotZero(res.vOs) ) res.vOs = Normalize(res.vOs); + if ( VNotZero(res.vOt) ) res.vOt = Normalize(res.vOt); + if (fAngleSum>0) + { + res.fMagS /= fAngleSum; + res.fMagT /= fAngleSum; + } + + return res; +} + +static tbool CompareSubGroups(const SSubGroup * pg1, const SSubGroup * pg2) +{ + tbool bStillSame=TTRUE; + int i=0; + if (pg1->iNrFaces!=pg2->iNrFaces) return TFALSE; + while (iiNrFaces && bStillSame) + { + bStillSame = pg1->pTriMembers[i]==pg2->pTriMembers[i] ? TTRUE : TFALSE; + if (bStillSame) ++i; + } + return bStillSame; +} + +static void QuickSort(int* pSortBuffer, int iLeft, int iRight, unsigned int uSeed) +{ + int iL, iR, n, index, iMid, iTmp; + + // Random + unsigned int t=uSeed&31; + t=(uSeed<>(32-t)); + uSeed=uSeed+t+3; + // Random end + + iL=iLeft; iR=iRight; + n = (iR-iL)+1; + assert(n>=0); + index = (int) (uSeed%n); + + iMid=pSortBuffer[index + iL]; + + + do + { + while (pSortBuffer[iL] < iMid) + ++iL; + while (pSortBuffer[iR] > iMid) + --iR; + + if (iL <= iR) + { + iTmp = pSortBuffer[iL]; + pSortBuffer[iL] = pSortBuffer[iR]; + pSortBuffer[iR] = iTmp; + ++iL; --iR; + } + } + while (iL <= iR); + + if (iLeft < iR) + QuickSort(pSortBuffer, iLeft, iR, uSeed); + if (iL < iRight) + QuickSort(pSortBuffer, iL, iRight, uSeed); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// + +static void QuickSortEdges(SEdge * pSortBuffer, int iLeft, int iRight, const int channel, unsigned int uSeed); +static void GetEdge(int * i0_out, int * i1_out, int * edgenum_out, const int indices[], const int i0_in, const int i1_in); + +static void BuildNeighborsFast(STriInfo pTriInfos[], SEdge * pEdges, const int piTriListIn[], const int iNrTrianglesIn) +{ + // build array of edges + unsigned int uSeed = INTERNAL_RND_SORT_SEED; // could replace with a random seed? + int iEntries=0, iCurStartIndex=-1, f=0, i=0; + for (f=0; f pSortBuffer[iRight].array[channel]) + { + sTmp = pSortBuffer[iLeft]; + pSortBuffer[iLeft] = pSortBuffer[iRight]; + pSortBuffer[iRight] = sTmp; + } + return; + } + + // Random + t=uSeed&31; + t=(uSeed<>(32-t)); + uSeed=uSeed+t+3; + // Random end + + iL = iLeft; + iR = iRight; + n = (iR-iL)+1; + assert(n>=0); + index = (int) (uSeed%n); + + iMid=pSortBuffer[index + iL].array[channel]; + + do + { + while (pSortBuffer[iL].array[channel] < iMid) + ++iL; + while (pSortBuffer[iR].array[channel] > iMid) + --iR; + + if (iL <= iR) + { + sTmp = pSortBuffer[iL]; + pSortBuffer[iL] = pSortBuffer[iR]; + pSortBuffer[iR] = sTmp; + ++iL; --iR; + } + } + while (iL <= iR); + + if (iLeft < iR) + QuickSortEdges(pSortBuffer, iLeft, iR, channel, uSeed); + if (iL < iRight) + QuickSortEdges(pSortBuffer, iL, iRight, channel, uSeed); +} + +// resolve ordering and edge number +static void GetEdge(int * i0_out, int * i1_out, int * edgenum_out, const int indices[], const int i0_in, const int i1_in) +{ + *edgenum_out = -1; + + // test if first index is on the edge + if (indices[0]==i0_in || indices[0]==i1_in) + { + // test if second index is on the edge + if (indices[1]==i0_in || indices[1]==i1_in) + { + edgenum_out[0]=0; // first edge + i0_out[0]=indices[0]; + i1_out[0]=indices[1]; + } + else + { + edgenum_out[0]=2; // third edge + i0_out[0]=indices[2]; + i1_out[0]=indices[0]; + } + } + else + { + // only second and third index is on the edge + edgenum_out[0]=1; // second edge + i0_out[0]=indices[1]; + i1_out[0]=indices[2]; + } +} + + +///////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////// Degenerate triangles //////////////////////////////////// + +static void DegenPrologue(STriInfo pTriInfos[], int piTriList_out[], const int iNrTrianglesIn, const int iTotTris) +{ + int iNextGoodTriangleSearchIndex=-1; + tbool bStillFindingGoodOnes; + + // locate quads with only one good triangle + int t=0; + while (t<(iTotTris-1)) + { + const int iFO_a = pTriInfos[t].iOrgFaceNumber; + const int iFO_b = pTriInfos[t+1].iOrgFaceNumber; + if (iFO_a==iFO_b) // this is a quad + { + const tbool bIsDeg_a = (pTriInfos[t].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE; + const tbool bIsDeg_b = (pTriInfos[t+1].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE; + if ((bIsDeg_a^bIsDeg_b)!=0) + { + pTriInfos[t].iFlag |= QUAD_ONE_DEGEN_TRI; + pTriInfos[t+1].iFlag |= QUAD_ONE_DEGEN_TRI; + } + t += 2; + } + else + ++t; + } + + // reorder list so all degen triangles are moved to the back + // without reordering the good triangles + iNextGoodTriangleSearchIndex = 1; + t=0; + bStillFindingGoodOnes = TTRUE; + while (t (t+1)); + + // swap triangle t0 and t1 + if (!bJustADegenerate) + { + int i=0; + for (i=0; i<3; i++) + { + const int index = piTriList_out[t0*3+i]; + piTriList_out[t0*3+i] = piTriList_out[t1*3+i]; + piTriList_out[t1*3+i] = index; + } + { + const STriInfo tri_info = pTriInfos[t0]; + pTriInfos[t0] = pTriInfos[t1]; + pTriInfos[t1] = tri_info; + } + } + else + bStillFindingGoodOnes = TFALSE; // this is not supposed to happen + } + + if (bStillFindingGoodOnes) ++t; + } + + assert(bStillFindingGoodOnes); // code will still work. + assert(iNrTrianglesIn == t); +} + +static void DegenEpilogue(STSpace psTspace[], STriInfo pTriInfos[], int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn, const int iTotTris) +{ + int t=0, i=0; + // deal with degenerate triangles + // punishment for degenerate triangles is O(N^2) + for (t=iNrTrianglesIn; t http://image.diku.dk/projects/media/morten.mikkelsen.08.pdf + * Note that though the tangent spaces at the vertices are generated in an order-independent way, + * by this implementation, the interpolated tangent space is still affected by which diagonal is + * chosen to split each quad. A sensible solution is to have your tools pipeline always + * split quads by the shortest diagonal. This choice is order-independent and works with mirroring. + * If these have the same length then compare the diagonals defined by the texture coordinates. + * XNormal which is a tool for baking normal maps allows you to write your own tangent space plugin + * and also quad triangulator plugin. + */ + + +typedef int tbool; +typedef struct SMikkTSpaceContext SMikkTSpaceContext; + +typedef struct { + // Returns the number of faces (triangles/quads) on the mesh to be processed. + int (*m_getNumFaces)(const SMikkTSpaceContext * pContext); + + // Returns the number of vertices on face number iFace + // iFace is a number in the range {0, 1, ..., getNumFaces()-1} + int (*m_getNumVerticesOfFace)(const SMikkTSpaceContext * pContext, const int iFace); + + // returns the position/normal/texcoord of the referenced face of vertex number iVert. + // iVert is in the range {0,1,2} for triangles and {0,1,2,3} for quads. + void (*m_getPosition)(const SMikkTSpaceContext * pContext, float fvPosOut[], const int iFace, const int iVert); + void (*m_getNormal)(const SMikkTSpaceContext * pContext, float fvNormOut[], const int iFace, const int iVert); + void (*m_getTexCoord)(const SMikkTSpaceContext * pContext, float fvTexcOut[], const int iFace, const int iVert); + + // either (or both) of the two setTSpace callbacks can be set. + // The call-back m_setTSpaceBasic() is sufficient for basic normal mapping. + + // This function is used to return the tangent and fSign to the application. + // fvTangent is a unit length vector. + // For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level. + // bitangent = fSign * cross(vN, tangent); + // Note that the results are returned unindexed. It is possible to generate a new index list + // But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results. + // DO NOT! use an already existing index list. + void (*m_setTSpaceBasic)(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert); + + // This function is used to return tangent space results to the application. + // fvTangent and fvBiTangent are unit length vectors and fMagS and fMagT are their + // true magnitudes which can be used for relief mapping effects. + // fvBiTangent is the "real" bitangent and thus may not be perpendicular to fvTangent. + // However, both are perpendicular to the vertex normal. + // For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level. + // fSign = bIsOrientationPreserving ? 1.0f : (-1.0f); + // bitangent = fSign * cross(vN, tangent); + // Note that the results are returned unindexed. It is possible to generate a new index list + // But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results. + // DO NOT! use an already existing index list. + void (*m_setTSpace)(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fvBiTangent[], const float fMagS, const float fMagT, + const tbool bIsOrientationPreserving, const int iFace, const int iVert); +} SMikkTSpaceInterface; + +struct SMikkTSpaceContext +{ + SMikkTSpaceInterface * m_pInterface; // initialized with callback functions + void * m_pUserData; // pointer to client side mesh data etc. (passed as the first parameter with every interface call) +}; + +// these are both thread safe! +tbool genTangSpaceDefault(const SMikkTSpaceContext * pContext); // Default (recommended) fAngularThreshold is 180 degrees (which means threshold disabled) +tbool genTangSpace(const SMikkTSpaceContext * pContext, const float fAngularThreshold); + + +// To avoid visual errors (distortions/unwanted hard edges in lighting), when using sampled normal maps, the +// normal map sampler must use the exact inverse of the pixel shader transformation. +// The most efficient transformation we can possibly do in the pixel shader is +// achieved by using, directly, the "unnormalized" interpolated tangent, bitangent and vertex normal: vT, vB and vN. +// pixel shader (fast transform out) +// vNout = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN ); +// where vNt is the tangent space normal. The normal map sampler must likewise use the +// interpolated and "unnormalized" tangent, bitangent and vertex normal to be compliant with the pixel shader. +// sampler does (exact inverse of pixel shader): +// float3 row0 = cross(vB, vN); +// float3 row1 = cross(vN, vT); +// float3 row2 = cross(vT, vB); +// float fSign = dot(vT, row0)<0 ? -1 : 1; +// vNt = normalize( fSign * float3(dot(vNout,row0), dot(vNout,row1), dot(vNout,row2)) ); +// where vNout is the sampled normal in some chosen 3D space. +// +// Should you choose to reconstruct the bitangent in the pixel shader instead +// of the vertex shader, as explained earlier, then be sure to do this in the normal map sampler also. +// Finally, beware of quad triangulations. If the normal map sampler doesn't use the same triangulation of +// quads as your renderer then problems will occur since the interpolated tangent spaces will differ +// eventhough the vertex level tangent spaces match. This can be solved either by triangulating before +// sampling/exporting or by using the order-independent choice of diagonal for splitting quads suggested earlier. +// However, this must be used both by the sampler and your tools/rendering pipeline. + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/crates/bevy_mikktspace/generator/src/obj_loader.c b/crates/bevy_mikktspace/generator/src/obj_loader.c new file mode 100644 index 0000000000000..dc4cf2b46111f --- /dev/null +++ b/crates/bevy_mikktspace/generator/src/obj_loader.c @@ -0,0 +1,67 @@ +#include "obj_loader.h" + +#include + +static float_t parse_float() { + char *token = strtok(NULL, " "); + return strtof(token, NULL); +} + +static vec3_t parse_vec3() { + float_t x = parse_float(); + float_t y = parse_float(); + float_t z = parse_float(); + vec3_t value = {x, y, z}; + return value; +} + +static vec2_t parse_vec2() { + float_t x = parse_float(); + float_t y = parse_float(); + vec2_t value = {x, y}; + return value; +} + +static mtg_obj_vertex_t parse_vertex() { + char *token = strtok(NULL, " "); + size_t position = strtoul(token, &token, 10); + size_t normal = strtoul(token + 1, &token, 10); + size_t texture_coords = strtoul(token + 1, &token, 10); + mtg_obj_vertex_t value = {position, normal, texture_coords}; + return value; +} + +void mtg_obj_parse_line(char *line, mtg_obj_data_t *data) { + // Lines are space-separated + char *token = strtok(line, " "); + + // First token is the command + if (strcmp(token, "v") == 0) { + // Vertex position + vec3_t position = parse_vec3(); + data->positions[data->positions_len] = position; + data->positions_len += 1; + } + else if (strcmp(token, "vn") == 0) { + // Vertex normal + vec3_t normal = parse_vec3(); + data->normals[data->normals_len] = normal; + data->normals_len += 1; + } + else if (strcmp(token, "vt") == 0) { + // Vertex texture coordinate + vec2_t texture_coords = parse_vec2(); + data->texture_coords[data->texture_coords_len] = texture_coords; + data->texture_coords_len += 1; + } + else if (strcmp(token, "f") == 0) { + // Face, currently always assuming tris + mtg_obj_vertex_t v0 = parse_vertex(); + mtg_obj_vertex_t v1 = parse_vertex(); + mtg_obj_vertex_t v2 = parse_vertex(); + + mtg_obj_face_t face = { { v0, v1, v2} }; + data->faces[data->faces_len] = face; + data->faces_len += 1; + } +} diff --git a/crates/bevy_mikktspace/generator/src/obj_loader.h b/crates/bevy_mikktspace/generator/src/obj_loader.h new file mode 100644 index 0000000000000..fc2d05fb3fce2 --- /dev/null +++ b/crates/bevy_mikktspace/generator/src/obj_loader.h @@ -0,0 +1,32 @@ +#pragma once + +#include "vmath.h" + +#include +#include + +typedef struct { + size_t position; + size_t normal; + size_t texture_coords; +} mtg_obj_vertex_t; + +typedef struct { + mtg_obj_vertex_t vertices[3]; +} mtg_obj_face_t; + +typedef struct { + vec3_t positions[1024]; + size_t positions_len; + + vec3_t normals[1024]; + size_t normals_len; + + vec2_t texture_coords[1024]; + size_t texture_coords_len; + + mtg_obj_face_t faces[1024]; + size_t faces_len; +} mtg_obj_data_t; + +void mtg_obj_parse_line(char *line, mtg_obj_data_t *data); diff --git a/crates/bevy_mikktspace/generator/src/vmath.h b/crates/bevy_mikktspace/generator/src/vmath.h new file mode 100644 index 0000000000000..e5c54fd8bc55b --- /dev/null +++ b/crates/bevy_mikktspace/generator/src/vmath.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +typedef struct { + float_t x, y; +} vec2_t; + +typedef struct { + float_t x, y, z; +} vec3_t; + +static bool vec2_eq(vec2_t a, vec2_t b) { + return a.x == b.x && a.y == b.y; +} + +static bool vec3_eq(vec3_t a, vec3_t b) { + return a.x == b.x && a.y == b.y && a.z == b.z; +} diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs deleted file mode 100644 index c1586235da489..0000000000000 --- a/crates/bevy_mikktspace/src/generated.rs +++ /dev/null @@ -1,1807 +0,0 @@ -//! Everything in this module is pending to be refactored, turned into idiomatic-rust, and moved to -//! other modules. - -//! The contents of this file are a combination of transpilation and human -//! modification to Morten S. Mikkelsen's original tangent space algorithm -//! implementation written in C. The original source code can be found at -//! -//! and includes the following licence: -//! -//! Copyright (C) 2011 by Morten S. Mikkelsen -//! -//! This software is provided 'as-is', without any express or implied -//! warranty. In no event will the authors be held liable for any damages -//! arising from the use of this software. -//! -//! Permission is granted to anyone to use this software for any purpose, -//! including commercial applications, and to alter it and redistribute it -//! freely, subject to the following restrictions: -//! -//! 1. The origin of this software must not be misrepresented; you must not -//! claim that you wrote the original software. If you use this software -//! in a product, an acknowledgment in the product documentation would be -//! appreciated but is not required. -//! -//! 2. Altered source versions must be plainly marked as such, and must not be -//! misrepresented as being the original software. -//! -//! 3. This notice may not be removed or altered from any source distribution. - -#![allow( - clippy::all, - clippy::doc_markdown, - clippy::redundant_else, - clippy::match_same_arms, - clippy::semicolon_if_nothing_returned, - clippy::explicit_iter_loop, - clippy::map_flatten, - dead_code, - mutable_transmutes, - non_camel_case_types, - non_snake_case, - non_upper_case_globals, - unused_mut, - unused_assignments, - unused_variables -)] - -use std::ptr::null_mut; - -use glam::Vec3; - -use crate::{face_vert_to_index, get_normal, get_position, get_tex_coord, Geometry}; - -#[derive(Copy, Clone)] -pub struct STSpace { - pub vOs: Vec3, - pub fMagS: f32, - pub vOt: Vec3, - pub fMagT: f32, - pub iCounter: i32, - pub bOrient: bool, -} - -impl STSpace { - pub fn zero() -> Self { - Self { - vOs: Default::default(), - fMagS: 0.0, - vOt: Default::default(), - fMagT: 0.0, - iCounter: 0, - bOrient: false, - } - } -} - -// To avoid visual errors (distortions/unwanted hard edges in lighting), when using sampled normal maps, the -// normal map sampler must use the exact inverse of the pixel shader transformation. -// The most efficient transformation we can possibly do in the pixel shader is -// achieved by using, directly, the "unnormalized" interpolated tangent, bitangent and vertex normal: vT, vB and vN. -// pixel shader (fast transform out) -// vNout = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN ); -// where vNt is the tangent space normal. The normal map sampler must likewise use the -// interpolated and "unnormalized" tangent, bitangent and vertex normal to be compliant with the pixel shader. -// sampler does (exact inverse of pixel shader): -// float3 row0 = cross(vB, vN); -// float3 row1 = cross(vN, vT); -// float3 row2 = cross(vT, vB); -// float fSign = dot(vT, row0)<0 ? -1 : 1; -// vNt = normalize( fSign * float3(dot(vNout,row0), dot(vNout,row1), dot(vNout,row2)) ); -// where vNout is the sampled normal in some chosen 3D space. -// -// Should you choose to reconstruct the bitangent in the pixel shader instead -// of the vertex shader, as explained earlier, then be sure to do this in the normal map sampler also. -// Finally, beware of quad triangulations. If the normal map sampler doesn't use the same triangulation of -// quads as your renderer then problems will occur since the interpolated tangent spaces will differ -// eventhough the vertex level tangent spaces match. This can be solved either by triangulating before -// sampling/exporting or by using the order-independent choice of diagonal for splitting quads suggested earlier. -// However, this must be used both by the sampler and your tools/rendering pipeline. -// internal structure - -#[derive(Copy, Clone)] -pub struct STriInfo { - pub FaceNeighbors: [i32; 3], - pub AssignedGroup: [*mut SGroup; 3], - pub vOs: Vec3, - pub vOt: Vec3, - pub fMagS: f32, - pub fMagT: f32, - pub iOrgFaceNumber: i32, - pub iFlag: i32, - pub iTSpacesOffs: i32, - pub vert_num: [u8; 4], -} - -impl STriInfo { - fn zero() -> Self { - Self { - FaceNeighbors: [0, 0, 0], - AssignedGroup: [null_mut(), null_mut(), null_mut()], - vOs: Default::default(), - vOt: Default::default(), - fMagS: 0.0, - fMagT: 0.0, - iOrgFaceNumber: 0, - iFlag: 0, - iTSpacesOffs: 0, - vert_num: [0, 0, 0, 0], - } - } -} - -#[derive(Copy, Clone)] -pub struct SGroup { - pub iNrFaces: i32, - pub pFaceIndices: *mut i32, - pub iVertexRepresentitive: i32, - pub bOrientPreservering: bool, -} - -impl SGroup { - fn zero() -> Self { - Self { - iNrFaces: 0, - pFaceIndices: null_mut(), - iVertexRepresentitive: 0, - bOrientPreservering: false, - } - } -} - -#[derive(Clone)] -pub struct SSubGroup { - pub iNrFaces: i32, - pub pTriMembers: Vec, -} - -impl SSubGroup { - fn zero() -> Self { - Self { - iNrFaces: 0, - pTriMembers: Vec::new(), - } - } -} - -#[derive(Copy, Clone)] -pub union SEdge { - pub unnamed: unnamed, - pub array: [i32; 3], -} - -impl SEdge { - fn zero() -> Self { - Self { array: [0, 0, 0] } - } -} - -#[derive(Copy, Clone)] -pub struct unnamed { - pub i0: i32, - pub i1: i32, - pub f: i32, -} - -#[derive(Copy, Clone)] -pub struct STmpVert { - pub vert: [f32; 3], - pub index: i32, -} - -impl STmpVert { - fn zero() -> Self { - Self { - vert: [0.0, 0.0, 0.0], - index: 0, - } - } -} - -pub unsafe fn genTangSpace(geometry: &mut I, fAngularThreshold: f32) -> bool { - let mut iNrTrianglesIn = 0; - let mut f = 0; - let mut t = 0; - let mut i = 0; - let mut iNrTSPaces = 0; - let mut iTotTris = 0; - let mut iDegenTriangles = 0; - let mut iNrMaxGroups = 0; - let mut iNrActiveGroups: i32 = 0i32; - let mut index = 0; - let iNrFaces = geometry.num_faces(); - let mut bRes: bool = false; - let fThresCos: f32 = - ((fAngularThreshold * 3.14159265358979323846f64 as f32 / 180.0f32) as f64).cos() as f32; - f = 0; - while f < iNrFaces { - let verts = geometry.num_vertices_of_face(f); - if verts == 3 { - iNrTrianglesIn += 1 - } else if verts == 4 { - iNrTrianglesIn += 2 - } - f += 1 - } - if iNrTrianglesIn <= 0 { - return false; - } - - let mut piTriListIn = vec![0i32; 3 * iNrTrianglesIn]; - let mut pTriInfos = vec![STriInfo::zero(); iNrTrianglesIn]; - - iNrTSPaces = GenerateInitialVerticesIndexList( - &mut pTriInfos, - &mut piTriListIn, - geometry, - iNrTrianglesIn, - ); - GenerateSharedVerticesIndexList(piTriListIn.as_mut_ptr(), geometry, iNrTrianglesIn); - iTotTris = iNrTrianglesIn; - iDegenTriangles = 0; - t = 0; - while t < iTotTris as usize { - let i0 = piTriListIn[t * 3 + 0]; - let i1 = piTriListIn[t * 3 + 1]; - let i2 = piTriListIn[t * 3 + 2]; - let p0 = get_position(geometry, i0 as usize); - let p1 = get_position(geometry, i1 as usize); - let p2 = get_position(geometry, i2 as usize); - if p0 == p1 || p0 == p2 || p1 == p2 { - pTriInfos[t].iFlag |= 1i32; - iDegenTriangles += 1 - } - t += 1 - } - iNrTrianglesIn = iTotTris - iDegenTriangles; - DegenPrologue( - pTriInfos.as_mut_ptr(), - piTriListIn.as_mut_ptr(), - iNrTrianglesIn as i32, - iTotTris as i32, - ); - InitTriInfo( - pTriInfos.as_mut_ptr(), - piTriListIn.as_ptr(), - geometry, - iNrTrianglesIn, - ); - iNrMaxGroups = iNrTrianglesIn * 3; - - let mut pGroups = vec![SGroup::zero(); iNrMaxGroups]; - let mut piGroupTrianglesBuffer = vec![0; iNrTrianglesIn * 3]; - - iNrActiveGroups = Build4RuleGroups( - pTriInfos.as_mut_ptr(), - pGroups.as_mut_ptr(), - piGroupTrianglesBuffer.as_mut_ptr(), - piTriListIn.as_ptr(), - iNrTrianglesIn as i32, - ); - - let mut psTspace = vec![ - STSpace { - vOs: Vec3::new(1.0, 0.0, 0.0), - fMagS: 1.0, - vOt: Vec3::new(0.0, 1.0, 0.0), - fMagT: 1.0, - ..STSpace::zero() - }; - iNrTSPaces - ]; - - bRes = GenerateTSpaces( - &mut psTspace, - pTriInfos.as_ptr(), - pGroups.as_ptr(), - iNrActiveGroups, - piTriListIn.as_ptr(), - fThresCos, - geometry, - ); - if !bRes { - return false; - } - DegenEpilogue( - psTspace.as_mut_ptr(), - pTriInfos.as_mut_ptr(), - piTriListIn.as_mut_ptr(), - geometry, - iNrTrianglesIn as i32, - iTotTris as i32, - ); - index = 0; - f = 0; - while f < iNrFaces { - let verts_0 = geometry.num_vertices_of_face(f); - if !(verts_0 != 3 && verts_0 != 4) { - i = 0; - while i < verts_0 { - let mut pTSpace: *const STSpace = &mut psTspace[index] as *mut STSpace; - let mut tang = Vec3::new((*pTSpace).vOs.x, (*pTSpace).vOs.y, (*pTSpace).vOs.z); - let mut bitang = Vec3::new((*pTSpace).vOt.x, (*pTSpace).vOt.y, (*pTSpace).vOt.z); - geometry.set_tangent( - tang.into(), - bitang.into(), - (*pTSpace).fMagS, - (*pTSpace).fMagT, - (*pTSpace).bOrient, - f, - i, - ); - index += 1; - i += 1 - } - } - f += 1 - } - - return true; -} -unsafe fn DegenEpilogue( - mut psTspace: *mut STSpace, - mut pTriInfos: *mut STriInfo, - mut piTriListIn: *mut i32, - geometry: &mut I, - iNrTrianglesIn: i32, - iTotTris: i32, -) { - let mut t: i32 = 0i32; - let mut i: i32 = 0i32; - t = iNrTrianglesIn; - while t < iTotTris { - let bSkip: bool = if (*pTriInfos.offset(t as isize)).iFlag & 2i32 != 0i32 { - true - } else { - false - }; - if !bSkip { - i = 0i32; - while i < 3i32 { - let index1: i32 = *piTriListIn.offset((t * 3i32 + i) as isize); - let mut bNotFound: bool = true; - let mut j: i32 = 0i32; - while bNotFound && j < 3i32 * iNrTrianglesIn { - let index2: i32 = *piTriListIn.offset(j as isize); - if index1 == index2 { - bNotFound = false - } else { - j += 1 - } - } - if !bNotFound { - let iTri: i32 = j / 3i32; - let iVert: i32 = j % 3i32; - let iSrcVert: i32 = - (*pTriInfos.offset(iTri as isize)).vert_num[iVert as usize] as i32; - let iSrcOffs: i32 = (*pTriInfos.offset(iTri as isize)).iTSpacesOffs; - let iDstVert: i32 = (*pTriInfos.offset(t as isize)).vert_num[i as usize] as i32; - let iDstOffs: i32 = (*pTriInfos.offset(t as isize)).iTSpacesOffs; - *psTspace.offset((iDstOffs + iDstVert) as isize) = - *psTspace.offset((iSrcOffs + iSrcVert) as isize) - } - i += 1 - } - } - t += 1 - } - t = 0i32; - while t < iNrTrianglesIn { - if (*pTriInfos.offset(t as isize)).iFlag & 2i32 != 0i32 { - let mut vDstP = Vec3::new(0.0, 0.0, 0.0); - let mut iOrgF: i32 = -1i32; - let mut i_0: i32 = 0i32; - let mut bNotFound_0: bool = false; - let mut pV: *mut u8 = (*pTriInfos.offset(t as isize)).vert_num.as_mut_ptr(); - let mut iFlag: i32 = 1i32 << *pV.offset(0isize) as i32 - | 1i32 << *pV.offset(1isize) as i32 - | 1i32 << *pV.offset(2isize) as i32; - let mut iMissingIndex: i32 = 0i32; - if iFlag & 2i32 == 0i32 { - iMissingIndex = 1i32 - } else if iFlag & 4i32 == 0i32 { - iMissingIndex = 2i32 - } else if iFlag & 8i32 == 0i32 { - iMissingIndex = 3i32 - } - iOrgF = (*pTriInfos.offset(t as isize)).iOrgFaceNumber; - vDstP = get_position( - geometry, - face_vert_to_index(iOrgF as usize, iMissingIndex as usize), - ); - bNotFound_0 = true; - i_0 = 0i32; - while bNotFound_0 && i_0 < 3i32 { - let iVert_0: i32 = *pV.offset(i_0 as isize) as i32; - let vSrcP = get_position( - geometry, - face_vert_to_index(iOrgF as usize, iVert_0 as usize), - ); - if vSrcP == vDstP { - let iOffs: i32 = (*pTriInfos.offset(t as isize)).iTSpacesOffs; - *psTspace.offset((iOffs + iMissingIndex) as isize) = - *psTspace.offset((iOffs + iVert_0) as isize); - bNotFound_0 = false - } else { - i_0 += 1 - } - } - } - t += 1 - } -} - -unsafe fn GenerateTSpaces( - psTspace: &mut [STSpace], - mut pTriInfos: *const STriInfo, - mut pGroups: *const SGroup, - iNrActiveGroups: i32, - mut piTriListIn: *const i32, - fThresCos: f32, - geometry: &mut I, -) -> bool { - let mut iMaxNrFaces: usize = 0; - let mut iUniqueTspaces = 0; - let mut g: i32 = 0i32; - let mut i: i32 = 0i32; - g = 0i32; - while g < iNrActiveGroups { - if iMaxNrFaces < (*pGroups.offset(g as isize)).iNrFaces as usize { - iMaxNrFaces = (*pGroups.offset(g as isize)).iNrFaces as usize - } - g += 1 - } - if iMaxNrFaces == 0 { - return true; - } - - let mut pSubGroupTspace = vec![STSpace::zero(); iMaxNrFaces]; - let mut pUniSubGroups = vec![SSubGroup::zero(); iMaxNrFaces]; - let mut pTmpMembers = vec![0i32; iMaxNrFaces]; - - iUniqueTspaces = 0; - g = 0i32; - while g < iNrActiveGroups { - let mut pGroup: *const SGroup = &*pGroups.offset(g as isize) as *const SGroup; - let mut iUniqueSubGroups = 0; - let mut s = 0; - i = 0i32; - while i < (*pGroup).iNrFaces { - let f: i32 = *(*pGroup).pFaceIndices.offset(i as isize); - let mut index: i32 = -1i32; - let mut iVertIndex: i32 = -1i32; - let mut iOF_1: i32 = -1i32; - let mut iMembers: usize = 0; - let mut j: i32 = 0i32; - let mut l: usize = 0; - let mut tmp_group: SSubGroup = SSubGroup { - iNrFaces: 0, - pTriMembers: Vec::new(), - }; - let mut bFound: bool = false; - let mut n = Vec3::new(0.0, 0.0, 0.0); - let mut vOs = Vec3::new(0.0, 0.0, 0.0); - let mut vOt = Vec3::new(0.0, 0.0, 0.0); - if (*pTriInfos.offset(f as isize)).AssignedGroup[0usize] == pGroup as *mut SGroup { - index = 0i32 - } else if (*pTriInfos.offset(f as isize)).AssignedGroup[1usize] == pGroup as *mut SGroup - { - index = 1i32 - } else if (*pTriInfos.offset(f as isize)).AssignedGroup[2usize] == pGroup as *mut SGroup - { - index = 2i32 - } - iVertIndex = *piTriListIn.offset((f * 3i32 + index) as isize); - n = get_normal(geometry, iVertIndex as usize); - let mut vOs = (*pTriInfos.offset(f as isize)).vOs - - (n.dot((*pTriInfos.offset(f as isize)).vOs) * n); - let mut vOt = (*pTriInfos.offset(f as isize)).vOt - - (n.dot((*pTriInfos.offset(f as isize)).vOt) * n); - if VNotZero(vOs) { - vOs = Normalize(vOs) - } - if VNotZero(vOt) { - vOt = Normalize(vOt) - } - iOF_1 = (*pTriInfos.offset(f as isize)).iOrgFaceNumber; - iMembers = 0; - j = 0i32; - while j < (*pGroup).iNrFaces { - let t: i32 = *(*pGroup).pFaceIndices.offset(j as isize); - let iOF_2: i32 = (*pTriInfos.offset(t as isize)).iOrgFaceNumber; - let mut vOs2 = (*pTriInfos.offset(t as isize)).vOs - - (n.dot((*pTriInfos.offset(t as isize)).vOs) * n); - let mut vOt2 = (*pTriInfos.offset(t as isize)).vOt - - (n.dot((*pTriInfos.offset(t as isize)).vOt) * n); - if VNotZero(vOs2) { - vOs2 = Normalize(vOs2) - } - if VNotZero(vOt2) { - vOt2 = Normalize(vOt2) - } - let bAny: bool = if ((*pTriInfos.offset(f as isize)).iFlag - | (*pTriInfos.offset(t as isize)).iFlag) - & 4i32 - != 0i32 - { - true - } else { - false - }; - let bSameOrgFace: bool = iOF_1 == iOF_2; - let fCosS: f32 = vOs.dot(vOs2); - let fCosT: f32 = vOt.dot(vOt2); - if bAny || bSameOrgFace || fCosS > fThresCos && fCosT > fThresCos { - let fresh0 = iMembers; - iMembers = iMembers + 1; - pTmpMembers[fresh0] = t - } - j += 1 - } - if iMembers > 1 { - let mut uSeed: u32 = 39871946i32 as u32; - QuickSort(pTmpMembers.as_mut_ptr(), 0i32, (iMembers - 1) as i32, uSeed); - } - tmp_group.iNrFaces = iMembers as i32; - tmp_group.pTriMembers = pTmpMembers.clone(); - bFound = false; - l = 0; - while l < iUniqueSubGroups && !bFound { - bFound = CompareSubGroups(&mut tmp_group, &mut pUniSubGroups[l]); - if !bFound { - l += 1 - } - } - if !bFound { - pUniSubGroups[iUniqueSubGroups].iNrFaces = iMembers as i32; - pUniSubGroups[iUniqueSubGroups].pTriMembers = tmp_group.pTriMembers.clone(); - - pSubGroupTspace[iUniqueSubGroups] = EvalTspace( - tmp_group.pTriMembers.as_mut_ptr(), - iMembers as i32, - piTriListIn, - pTriInfos, - geometry, - (*pGroup).iVertexRepresentitive, - ); - iUniqueSubGroups += 1 - } - let iOffs = (*pTriInfos.offset(f as isize)).iTSpacesOffs as usize; - let iVert = (*pTriInfos.offset(f as isize)).vert_num[index as usize] as usize; - let mut pTS_out: *mut STSpace = &mut psTspace[iOffs + iVert] as *mut STSpace; - if (*pTS_out).iCounter == 1i32 { - *pTS_out = AvgTSpace(pTS_out, &mut pSubGroupTspace[l]); - (*pTS_out).iCounter = 2i32; - (*pTS_out).bOrient = (*pGroup).bOrientPreservering - } else { - *pTS_out = pSubGroupTspace[l]; - (*pTS_out).iCounter = 1i32; - (*pTS_out).bOrient = (*pGroup).bOrientPreservering - } - i += 1 - } - iUniqueTspaces += iUniqueSubGroups; - g += 1 - } - return true; -} -unsafe fn AvgTSpace(mut pTS0: *const STSpace, mut pTS1: *const STSpace) -> STSpace { - let mut ts_res: STSpace = STSpace { - vOs: Vec3::new(0.0, 0.0, 0.0), - fMagS: 0., - vOt: Vec3::new(0.0, 0.0, 0.0), - fMagT: 0., - iCounter: 0, - bOrient: false, - }; - if (*pTS0).fMagS == (*pTS1).fMagS - && (*pTS0).fMagT == (*pTS1).fMagT - && (*pTS0).vOs == (*pTS1).vOs - && (*pTS0).vOt == (*pTS1).vOt - { - ts_res.fMagS = (*pTS0).fMagS; - ts_res.fMagT = (*pTS0).fMagT; - ts_res.vOs = (*pTS0).vOs; - ts_res.vOt = (*pTS0).vOt - } else { - ts_res.fMagS = 0.5f32 * ((*pTS0).fMagS + (*pTS1).fMagS); - ts_res.fMagT = 0.5f32 * ((*pTS0).fMagT + (*pTS1).fMagT); - ts_res.vOs = (*pTS0).vOs + (*pTS1).vOs; - ts_res.vOt = (*pTS0).vOt + (*pTS1).vOt; - if VNotZero(ts_res.vOs) { - ts_res.vOs = Normalize(ts_res.vOs) - } - if VNotZero(ts_res.vOt) { - ts_res.vOt = Normalize(ts_res.vOt) - } - } - return ts_res; -} - -unsafe fn Normalize(v: Vec3) -> Vec3 { - return (1.0 / v.length()) * v; -} - -unsafe fn VNotZero(v: Vec3) -> bool { - NotZero(v.x) || NotZero(v.y) || NotZero(v.z) -} - -unsafe fn NotZero(fX: f32) -> bool { - fX.abs() > 1.17549435e-38f32 -} - -unsafe fn EvalTspace( - mut face_indices: *mut i32, - iFaces: i32, - mut piTriListIn: *const i32, - mut pTriInfos: *const STriInfo, - geometry: &mut I, - iVertexRepresentitive: i32, -) -> STSpace { - let mut res: STSpace = STSpace { - vOs: Vec3::new(0.0, 0.0, 0.0), - fMagS: 0., - vOt: Vec3::new(0.0, 0.0, 0.0), - fMagT: 0., - iCounter: 0, - bOrient: false, - }; - let mut fAngleSum: f32 = 0i32 as f32; - let mut face: i32 = 0i32; - res.vOs.x = 0.0f32; - res.vOs.y = 0.0f32; - res.vOs.z = 0.0f32; - res.vOt.x = 0.0f32; - res.vOt.y = 0.0f32; - res.vOt.z = 0.0f32; - res.fMagS = 0i32 as f32; - res.fMagT = 0i32 as f32; - face = 0i32; - while face < iFaces { - let f: i32 = *face_indices.offset(face as isize); - if (*pTriInfos.offset(f as isize)).iFlag & 4i32 == 0i32 { - let mut n = Vec3::new(0.0, 0.0, 0.0); - let mut vOs = Vec3::new(0.0, 0.0, 0.0); - let mut vOt = Vec3::new(0.0, 0.0, 0.0); - let mut p0 = Vec3::new(0.0, 0.0, 0.0); - let mut p1 = Vec3::new(0.0, 0.0, 0.0); - let mut p2 = Vec3::new(0.0, 0.0, 0.0); - let mut v1 = Vec3::new(0.0, 0.0, 0.0); - let mut v2 = Vec3::new(0.0, 0.0, 0.0); - let mut fCos: f32 = 0.; - let mut fAngle: f32 = 0.; - let mut fMagS: f32 = 0.; - let mut fMagT: f32 = 0.; - let mut i: i32 = -1i32; - let mut index: i32 = -1i32; - let mut i0: i32 = -1i32; - let mut i1: i32 = -1i32; - let mut i2: i32 = -1i32; - if *piTriListIn.offset((3i32 * f + 0i32) as isize) == iVertexRepresentitive { - i = 0i32 - } else if *piTriListIn.offset((3i32 * f + 1i32) as isize) == iVertexRepresentitive { - i = 1i32 - } else if *piTriListIn.offset((3i32 * f + 2i32) as isize) == iVertexRepresentitive { - i = 2i32 - } - index = *piTriListIn.offset((3i32 * f + i) as isize); - n = get_normal(geometry, index as usize); - let mut vOs = (*pTriInfos.offset(f as isize)).vOs - - (n.dot((*pTriInfos.offset(f as isize)).vOs) * n); - let mut vOt = (*pTriInfos.offset(f as isize)).vOt - - (n.dot((*pTriInfos.offset(f as isize)).vOt) * n); - if VNotZero(vOs) { - vOs = Normalize(vOs) - } - if VNotZero(vOt) { - vOt = Normalize(vOt) - } - i2 = *piTriListIn.offset((3i32 * f + if i < 2i32 { i + 1i32 } else { 0i32 }) as isize); - i1 = *piTriListIn.offset((3i32 * f + i) as isize); - i0 = *piTriListIn.offset((3i32 * f + if i > 0i32 { i - 1i32 } else { 2i32 }) as isize); - p0 = get_position(geometry, i0 as usize); - p1 = get_position(geometry, i1 as usize); - p2 = get_position(geometry, i2 as usize); - v1 = p0 - p1; - v2 = p2 - p1; - let mut v1 = v1 - (n.dot(v1) * n); - if VNotZero(v1) { - v1 = Normalize(v1) - } - let mut v2 = v2 - (n.dot(v2) * n); - if VNotZero(v2) { - v2 = Normalize(v2) - } - let fCos = v1.dot(v2); - - let fCos = if fCos > 1i32 as f32 { - 1i32 as f32 - } else if fCos < -1i32 as f32 { - -1i32 as f32 - } else { - fCos - }; - fAngle = (fCos as f64).acos() as f32; - fMagS = (*pTriInfos.offset(f as isize)).fMagS; - fMagT = (*pTriInfos.offset(f as isize)).fMagT; - res.vOs = res.vOs + (fAngle * vOs); - res.vOt = res.vOt + (fAngle * vOt); - res.fMagS += fAngle * fMagS; - res.fMagT += fAngle * fMagT; - fAngleSum += fAngle - } - face += 1 - } - if VNotZero(res.vOs) { - res.vOs = Normalize(res.vOs) - } - if VNotZero(res.vOt) { - res.vOt = Normalize(res.vOt) - } - if fAngleSum > 0i32 as f32 { - res.fMagS /= fAngleSum; - res.fMagT /= fAngleSum - } - return res; -} - -unsafe fn CompareSubGroups(mut pg1: *const SSubGroup, mut pg2: *const SSubGroup) -> bool { - let mut bStillSame: bool = true; - let mut i = 0; - if (*pg1).iNrFaces != (*pg2).iNrFaces { - return false; - } - while i < (*pg1).iNrFaces as usize && bStillSame { - bStillSame = if (*pg1).pTriMembers[i] == (*pg2).pTriMembers[i] { - true - } else { - false - }; - if bStillSame { - i += 1 - } - } - return bStillSame; -} -unsafe fn QuickSort(mut pSortBuffer: *mut i32, mut iLeft: i32, mut iRight: i32, mut uSeed: u32) { - let mut iL: i32 = 0; - let mut iR: i32 = 0; - let mut n: i32 = 0; - let mut index: i32 = 0; - let mut iMid: i32 = 0; - let mut iTmp: i32 = 0; - - // Random - let mut t: u32 = uSeed & 31i32 as u32; - t = uSeed.rotate_left(t) | uSeed.rotate_right((32i32 as u32).wrapping_sub(t)); - uSeed = uSeed.wrapping_add(t).wrapping_add(3i32 as u32); - // Random end - - iL = iLeft; - iR = iRight; - n = iR - iL + 1i32; - index = uSeed.wrapping_rem(n as u32) as i32; - iMid = *pSortBuffer.offset((index + iL) as isize); - loop { - while *pSortBuffer.offset(iL as isize) < iMid { - iL += 1 - } - while *pSortBuffer.offset(iR as isize) > iMid { - iR -= 1 - } - if iL <= iR { - iTmp = *pSortBuffer.offset(iL as isize); - *pSortBuffer.offset(iL as isize) = *pSortBuffer.offset(iR as isize); - *pSortBuffer.offset(iR as isize) = iTmp; - iL += 1; - iR -= 1 - } - if !(iL <= iR) { - break; - } - } - if iLeft < iR { - QuickSort(pSortBuffer, iLeft, iR, uSeed); - } - if iL < iRight { - QuickSort(pSortBuffer, iL, iRight, uSeed); - }; -} -unsafe fn Build4RuleGroups( - mut pTriInfos: *mut STriInfo, - mut pGroups: *mut SGroup, - mut piGroupTrianglesBuffer: *mut i32, - mut piTriListIn: *const i32, - iNrTrianglesIn: i32, -) -> i32 { - let iNrMaxGroups: i32 = iNrTrianglesIn * 3i32; - let mut iNrActiveGroups: i32 = 0i32; - let mut iOffset: i32 = 0i32; - let mut f: i32 = 0i32; - let mut i: i32 = 0i32; - f = 0i32; - while f < iNrTrianglesIn { - i = 0i32; - while i < 3i32 { - if (*pTriInfos.offset(f as isize)).iFlag & 4i32 == 0i32 - && (*pTriInfos.offset(f as isize)).AssignedGroup[i as usize].is_null() - { - let mut bOrPre: bool = false; - let mut neigh_indexL: i32 = 0; - let mut neigh_indexR: i32 = 0; - let vert_index: i32 = *piTriListIn.offset((f * 3i32 + i) as isize); - let ref mut fresh2 = (*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]; - *fresh2 = &mut *pGroups.offset(iNrActiveGroups as isize) as *mut SGroup; - (*(*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]) - .iVertexRepresentitive = vert_index; - (*(*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]).bOrientPreservering = - (*pTriInfos.offset(f as isize)).iFlag & 8i32 != 0i32; - (*(*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]).iNrFaces = 0i32; - let ref mut fresh3 = - (*(*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]).pFaceIndices; - *fresh3 = &mut *piGroupTrianglesBuffer.offset(iOffset as isize) as *mut i32; - iNrActiveGroups += 1; - AddTriToGroup((*pTriInfos.offset(f as isize)).AssignedGroup[i as usize], f); - bOrPre = if (*pTriInfos.offset(f as isize)).iFlag & 8i32 != 0i32 { - true - } else { - false - }; - neigh_indexL = (*pTriInfos.offset(f as isize)).FaceNeighbors[i as usize]; - neigh_indexR = (*pTriInfos.offset(f as isize)).FaceNeighbors - [(if i > 0i32 { i - 1i32 } else { 2i32 }) as usize]; - if neigh_indexL >= 0i32 { - let bAnswer: bool = AssignRecur( - piTriListIn, - pTriInfos, - neigh_indexL, - (*pTriInfos.offset(f as isize)).AssignedGroup[i as usize], - ); - let bOrPre2: bool = - if (*pTriInfos.offset(neigh_indexL as isize)).iFlag & 8i32 != 0i32 { - true - } else { - false - }; - let bDiff: bool = if bOrPre != bOrPre2 { true } else { false }; - } - if neigh_indexR >= 0i32 { - let bAnswer_0: bool = AssignRecur( - piTriListIn, - pTriInfos, - neigh_indexR, - (*pTriInfos.offset(f as isize)).AssignedGroup[i as usize], - ); - let bOrPre2_0: bool = - if (*pTriInfos.offset(neigh_indexR as isize)).iFlag & 8i32 != 0i32 { - true - } else { - false - }; - let bDiff_0: bool = if bOrPre != bOrPre2_0 { true } else { false }; - } - iOffset += (*(*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]).iNrFaces - } - i += 1 - } - f += 1 - } - return iNrActiveGroups; -} -// /////////////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////////////// -unsafe fn AssignRecur( - mut piTriListIn: *const i32, - mut psTriInfos: *mut STriInfo, - iMyTriIndex: i32, - mut pGroup: *mut SGroup, -) -> bool { - let mut pMyTriInfo: *mut STriInfo = - &mut *psTriInfos.offset(iMyTriIndex as isize) as *mut STriInfo; - // track down vertex - let iVertRep: i32 = (*pGroup).iVertexRepresentitive; - let mut pVerts: *const i32 = - &*piTriListIn.offset((3i32 * iMyTriIndex + 0i32) as isize) as *const i32; - let mut i: i32 = -1i32; - if *pVerts.offset(0isize) == iVertRep { - i = 0i32 - } else if *pVerts.offset(1isize) == iVertRep { - i = 1i32 - } else if *pVerts.offset(2isize) == iVertRep { - i = 2i32 - } - if (*pMyTriInfo).AssignedGroup[i as usize] == pGroup { - return true; - } else { - if !(*pMyTriInfo).AssignedGroup[i as usize].is_null() { - return false; - } - } - if (*pMyTriInfo).iFlag & 4i32 != 0i32 { - if (*pMyTriInfo).AssignedGroup[0usize].is_null() - && (*pMyTriInfo).AssignedGroup[1usize].is_null() - && (*pMyTriInfo).AssignedGroup[2usize].is_null() - { - (*pMyTriInfo).iFlag &= !8i32; - (*pMyTriInfo).iFlag |= if (*pGroup).bOrientPreservering { - 8i32 - } else { - 0i32 - } - } - } - let bOrient: bool = if (*pMyTriInfo).iFlag & 8i32 != 0i32 { - true - } else { - false - }; - if bOrient != (*pGroup).bOrientPreservering { - return false; - } - AddTriToGroup(pGroup, iMyTriIndex); - (*pMyTriInfo).AssignedGroup[i as usize] = pGroup; - let neigh_indexL: i32 = (*pMyTriInfo).FaceNeighbors[i as usize]; - let neigh_indexR: i32 = - (*pMyTriInfo).FaceNeighbors[(if i > 0i32 { i - 1i32 } else { 2i32 }) as usize]; - if neigh_indexL >= 0i32 { - AssignRecur(piTriListIn, psTriInfos, neigh_indexL, pGroup); - } - if neigh_indexR >= 0i32 { - AssignRecur(piTriListIn, psTriInfos, neigh_indexR, pGroup); - } - return true; -} -unsafe fn AddTriToGroup(mut pGroup: *mut SGroup, iTriIndex: i32) { - *(*pGroup).pFaceIndices.offset((*pGroup).iNrFaces as isize) = iTriIndex; - (*pGroup).iNrFaces += 1; -} -unsafe fn InitTriInfo( - mut pTriInfos: *mut STriInfo, - mut piTriListIn: *const i32, - geometry: &mut I, - iNrTrianglesIn: usize, -) { - let mut f = 0; - let mut i = 0; - let mut t = 0; - f = 0; - while f < iNrTrianglesIn { - i = 0i32; - while i < 3i32 { - (*pTriInfos.offset(f as isize)).FaceNeighbors[i as usize] = -1i32; - let ref mut fresh4 = (*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]; - *fresh4 = 0 as *mut SGroup; - (*pTriInfos.offset(f as isize)).vOs.x = 0.0f32; - (*pTriInfos.offset(f as isize)).vOs.y = 0.0f32; - (*pTriInfos.offset(f as isize)).vOs.z = 0.0f32; - (*pTriInfos.offset(f as isize)).vOt.x = 0.0f32; - (*pTriInfos.offset(f as isize)).vOt.y = 0.0f32; - (*pTriInfos.offset(f as isize)).vOt.z = 0.0f32; - (*pTriInfos.offset(f as isize)).fMagS = 0i32 as f32; - (*pTriInfos.offset(f as isize)).fMagT = 0i32 as f32; - (*pTriInfos.offset(f as isize)).iFlag |= 4i32; - i += 1 - } - f += 1 - } - f = 0; - while f < iNrTrianglesIn { - let v1 = get_position(geometry, *piTriListIn.offset((f * 3 + 0) as isize) as usize); - let v2 = get_position(geometry, *piTriListIn.offset((f * 3 + 1) as isize) as usize); - let v3 = get_position(geometry, *piTriListIn.offset((f * 3 + 2) as isize) as usize); - let t1 = get_tex_coord(geometry, *piTriListIn.offset((f * 3 + 0) as isize) as usize); - let t2 = get_tex_coord(geometry, *piTriListIn.offset((f * 3 + 1) as isize) as usize); - let t3 = get_tex_coord(geometry, *piTriListIn.offset((f * 3 + 2) as isize) as usize); - let t21x: f32 = t2.x - t1.x; - let t21y: f32 = t2.y - t1.y; - let t31x: f32 = t3.x - t1.x; - let t31y: f32 = t3.y - t1.y; - let d1 = v2 - v1; - let d2 = v3 - v1; - let fSignedAreaSTx2: f32 = t21x * t31y - t21y * t31x; - let mut vOs = (t31y * d1) - (t21y * d2); - let mut vOt = (-t31x * d1) + (t21x * d2); - (*pTriInfos.offset(f as isize)).iFlag |= if fSignedAreaSTx2 > 0i32 as f32 { - 8i32 - } else { - 0i32 - }; - if NotZero(fSignedAreaSTx2) { - let fAbsArea: f32 = fSignedAreaSTx2.abs(); - let fLenOs: f32 = vOs.length(); - let fLenOt: f32 = vOt.length(); - let fS: f32 = if (*pTriInfos.offset(f as isize)).iFlag & 8i32 == 0i32 { - -1.0f32 - } else { - 1.0f32 - }; - if NotZero(fLenOs) { - (*pTriInfos.offset(f as isize)).vOs = (fS / fLenOs) * vOs - } - if NotZero(fLenOt) { - (*pTriInfos.offset(f as isize)).vOt = (fS / fLenOt) * vOt - } - (*pTriInfos.offset(f as isize)).fMagS = fLenOs / fAbsArea; - (*pTriInfos.offset(f as isize)).fMagT = fLenOt / fAbsArea; - if NotZero((*pTriInfos.offset(f as isize)).fMagS) - && NotZero((*pTriInfos.offset(f as isize)).fMagT) - { - (*pTriInfos.offset(f as isize)).iFlag &= !4i32 - } - } - f += 1 - } - while t < iNrTrianglesIn - 1 { - let iFO_a: i32 = (*pTriInfos.offset(t as isize)).iOrgFaceNumber; - let iFO_b: i32 = (*pTriInfos.offset((t + 1) as isize)).iOrgFaceNumber; - if iFO_a == iFO_b { - let bIsDeg_a: bool = if (*pTriInfos.offset(t as isize)).iFlag & 1i32 != 0i32 { - true - } else { - false - }; - let bIsDeg_b: bool = if (*pTriInfos.offset((t + 1) as isize)).iFlag & 1i32 != 0i32 { - true - } else { - false - }; - if !(bIsDeg_a || bIsDeg_b) { - let bOrientA: bool = if (*pTriInfos.offset(t as isize)).iFlag & 8i32 != 0i32 { - true - } else { - false - }; - let bOrientB: bool = if (*pTriInfos.offset((t + 1) as isize)).iFlag & 8i32 != 0i32 { - true - } else { - false - }; - if bOrientA != bOrientB { - let mut bChooseOrientFirstTri: bool = false; - if (*pTriInfos.offset((t + 1) as isize)).iFlag & 4i32 != 0i32 { - bChooseOrientFirstTri = true - } else if CalcTexArea(geometry, piTriListIn.offset((t * 3 + 0) as isize)) - >= CalcTexArea(geometry, piTriListIn.offset(((t + 1) * 3 + 0) as isize)) - { - bChooseOrientFirstTri = true - } - let t0 = if bChooseOrientFirstTri { t } else { t + 1 }; - let t1_0 = if bChooseOrientFirstTri { t + 1 } else { t }; - (*pTriInfos.offset(t1_0 as isize)).iFlag &= !8i32; - (*pTriInfos.offset(t1_0 as isize)).iFlag |= - (*pTriInfos.offset(t0 as isize)).iFlag & 8i32 - } - } - t += 2 - } else { - t += 1 - } - } - - let mut pEdges = vec![SEdge::zero(); iNrTrianglesIn * 3]; - BuildNeighborsFast( - pTriInfos, - pEdges.as_mut_ptr(), - piTriListIn, - iNrTrianglesIn as i32, - ); -} - -unsafe fn BuildNeighborsFast( - mut pTriInfos: *mut STriInfo, - mut pEdges: *mut SEdge, - mut piTriListIn: *const i32, - iNrTrianglesIn: i32, -) { - // build array of edges - // could replace with a random seed? - let mut uSeed: u32 = 39871946i32 as u32; - let mut iEntries: i32 = 0i32; - let mut iCurStartIndex: i32 = -1i32; - let mut f: i32 = 0i32; - let mut i: i32 = 0i32; - f = 0i32; - while f < iNrTrianglesIn { - i = 0i32; - while i < 3i32 { - let i0: i32 = *piTriListIn.offset((f * 3i32 + i) as isize); - let i1: i32 = - *piTriListIn.offset((f * 3i32 + if i < 2i32 { i + 1i32 } else { 0i32 }) as isize); - (*pEdges.offset((f * 3i32 + i) as isize)).unnamed.i0 = if i0 < i1 { i0 } else { i1 }; - (*pEdges.offset((f * 3i32 + i) as isize)).unnamed.i1 = if !(i0 < i1) { i0 } else { i1 }; - (*pEdges.offset((f * 3i32 + i) as isize)).unnamed.f = f; - i += 1 - } - f += 1 - } - QuickSortEdges(pEdges, 0i32, iNrTrianglesIn * 3i32 - 1i32, 0i32, uSeed); - iEntries = iNrTrianglesIn * 3i32; - iCurStartIndex = 0i32; - i = 1i32; - while i < iEntries { - if (*pEdges.offset(iCurStartIndex as isize)).unnamed.i0 - != (*pEdges.offset(i as isize)).unnamed.i0 - { - let iL: i32 = iCurStartIndex; - let iR: i32 = i - 1i32; - iCurStartIndex = i; - QuickSortEdges(pEdges, iL, iR, 1i32, uSeed); - } - i += 1 - } - iCurStartIndex = 0i32; - i = 1i32; - while i < iEntries { - if (*pEdges.offset(iCurStartIndex as isize)).unnamed.i0 - != (*pEdges.offset(i as isize)).unnamed.i0 - || (*pEdges.offset(iCurStartIndex as isize)).unnamed.i1 - != (*pEdges.offset(i as isize)).unnamed.i1 - { - let iL_0: i32 = iCurStartIndex; - let iR_0: i32 = i - 1i32; - iCurStartIndex = i; - QuickSortEdges(pEdges, iL_0, iR_0, 2i32, uSeed); - } - i += 1 - } - i = 0i32; - while i < iEntries { - let i0_0: i32 = (*pEdges.offset(i as isize)).unnamed.i0; - let i1_0: i32 = (*pEdges.offset(i as isize)).unnamed.i1; - let f_0: i32 = (*pEdges.offset(i as isize)).unnamed.f; - let mut bUnassigned_A: bool = false; - let mut i0_A: i32 = 0; - let mut i1_A: i32 = 0; - let mut edgenum_A: i32 = 0; - let mut edgenum_B: i32 = 0i32; - GetEdge( - &mut i0_A, - &mut i1_A, - &mut edgenum_A, - &*piTriListIn.offset((f_0 * 3i32) as isize), - i0_0, - i1_0, - ); - bUnassigned_A = - if (*pTriInfos.offset(f_0 as isize)).FaceNeighbors[edgenum_A as usize] == -1i32 { - true - } else { - false - }; - if bUnassigned_A { - let mut j: i32 = i + 1i32; - let mut t: i32 = 0; - let mut bNotFound: bool = true; - while j < iEntries - && i0_0 == (*pEdges.offset(j as isize)).unnamed.i0 - && i1_0 == (*pEdges.offset(j as isize)).unnamed.i1 - && bNotFound - { - let mut bUnassigned_B: bool = false; - let mut i0_B: i32 = 0; - let mut i1_B: i32 = 0; - t = (*pEdges.offset(j as isize)).unnamed.f; - GetEdge( - &mut i1_B, - &mut i0_B, - &mut edgenum_B, - &*piTriListIn.offset((t * 3i32) as isize), - (*pEdges.offset(j as isize)).unnamed.i0, - (*pEdges.offset(j as isize)).unnamed.i1, - ); - bUnassigned_B = - if (*pTriInfos.offset(t as isize)).FaceNeighbors[edgenum_B as usize] == -1i32 { - true - } else { - false - }; - if i0_A == i0_B && i1_A == i1_B && bUnassigned_B { - bNotFound = false - } else { - j += 1 - } - } - if !bNotFound { - let mut t_0: i32 = (*pEdges.offset(j as isize)).unnamed.f; - (*pTriInfos.offset(f_0 as isize)).FaceNeighbors[edgenum_A as usize] = t_0; - (*pTriInfos.offset(t_0 as isize)).FaceNeighbors[edgenum_B as usize] = f_0 - } - } - i += 1 - } -} -unsafe fn GetEdge( - mut i0_out: *mut i32, - mut i1_out: *mut i32, - mut edgenum_out: *mut i32, - mut indices: *const i32, - i0_in: i32, - i1_in: i32, -) { - *edgenum_out = -1i32; - if *indices.offset(0isize) == i0_in || *indices.offset(0isize) == i1_in { - if *indices.offset(1isize) == i0_in || *indices.offset(1isize) == i1_in { - *edgenum_out.offset(0isize) = 0i32; - *i0_out.offset(0isize) = *indices.offset(0isize); - *i1_out.offset(0isize) = *indices.offset(1isize) - } else { - *edgenum_out.offset(0isize) = 2i32; - *i0_out.offset(0isize) = *indices.offset(2isize); - *i1_out.offset(0isize) = *indices.offset(0isize) - } - } else { - *edgenum_out.offset(0isize) = 1i32; - *i0_out.offset(0isize) = *indices.offset(1isize); - *i1_out.offset(0isize) = *indices.offset(2isize) - }; -} -// /////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////// -unsafe fn QuickSortEdges( - mut pSortBuffer: *mut SEdge, - mut iLeft: i32, - mut iRight: i32, - channel: i32, - mut uSeed: u32, -) { - let mut t: u32 = 0; - let mut iL: i32 = 0; - let mut iR: i32 = 0; - let mut n: i32 = 0; - let mut index: i32 = 0; - let mut iMid: i32 = 0; - // early out - let mut sTmp: SEdge = SEdge { - unnamed: unnamed { i0: 0, i1: 0, f: 0 }, - }; - let iElems: i32 = iRight - iLeft + 1i32; - if iElems < 2i32 { - return; - } else { - if iElems == 2i32 { - if (*pSortBuffer.offset(iLeft as isize)).array[channel as usize] - > (*pSortBuffer.offset(iRight as isize)).array[channel as usize] - { - sTmp = *pSortBuffer.offset(iLeft as isize); - *pSortBuffer.offset(iLeft as isize) = *pSortBuffer.offset(iRight as isize); - *pSortBuffer.offset(iRight as isize) = sTmp - } - return; - } - } - - // Random - t = uSeed & 31i32 as u32; - t = uSeed.rotate_left(t) | uSeed.rotate_right((32i32 as u32).wrapping_sub(t)); - uSeed = uSeed.wrapping_add(t).wrapping_add(3i32 as u32); - // Random end - - iL = iLeft; - iR = iRight; - n = iR - iL + 1i32; - index = uSeed.wrapping_rem(n as u32) as i32; - iMid = (*pSortBuffer.offset((index + iL) as isize)).array[channel as usize]; - loop { - while (*pSortBuffer.offset(iL as isize)).array[channel as usize] < iMid { - iL += 1 - } - while (*pSortBuffer.offset(iR as isize)).array[channel as usize] > iMid { - iR -= 1 - } - if iL <= iR { - sTmp = *pSortBuffer.offset(iL as isize); - *pSortBuffer.offset(iL as isize) = *pSortBuffer.offset(iR as isize); - *pSortBuffer.offset(iR as isize) = sTmp; - iL += 1; - iR -= 1 - } - if !(iL <= iR) { - break; - } - } - if iLeft < iR { - QuickSortEdges(pSortBuffer, iLeft, iR, channel, uSeed); - } - if iL < iRight { - QuickSortEdges(pSortBuffer, iL, iRight, channel, uSeed); - }; -} - -// returns the texture area times 2 -unsafe fn CalcTexArea(geometry: &mut I, mut indices: *const i32) -> f32 { - let t1 = get_tex_coord(geometry, *indices.offset(0isize) as usize); - let t2 = get_tex_coord(geometry, *indices.offset(1isize) as usize); - let t3 = get_tex_coord(geometry, *indices.offset(2isize) as usize); - let t21x: f32 = t2.x - t1.x; - let t21y: f32 = t2.y - t1.y; - let t31x: f32 = t3.x - t1.x; - let t31y: f32 = t3.y - t1.y; - let fSignedAreaSTx2: f32 = t21x * t31y - t21y * t31x; - return if fSignedAreaSTx2 < 0i32 as f32 { - -fSignedAreaSTx2 - } else { - fSignedAreaSTx2 - }; -} - -// degen triangles -unsafe fn DegenPrologue( - mut pTriInfos: *mut STriInfo, - mut piTriList_out: *mut i32, - iNrTrianglesIn: i32, - iTotTris: i32, -) { - let mut iNextGoodTriangleSearchIndex: i32 = -1i32; - let mut bStillFindingGoodOnes: bool = false; - // locate quads with only one good triangle - let mut t: i32 = 0i32; - while t < iTotTris - 1i32 { - let iFO_a: i32 = (*pTriInfos.offset(t as isize)).iOrgFaceNumber; - let iFO_b: i32 = (*pTriInfos.offset((t + 1i32) as isize)).iOrgFaceNumber; - if iFO_a == iFO_b { - let bIsDeg_a: bool = if (*pTriInfos.offset(t as isize)).iFlag & 1i32 != 0i32 { - true - } else { - false - }; - let bIsDeg_b: bool = if (*pTriInfos.offset((t + 1i32) as isize)).iFlag & 1i32 != 0i32 { - true - } else { - false - }; - if bIsDeg_a ^ bIsDeg_b != false { - (*pTriInfos.offset(t as isize)).iFlag |= 2i32; - (*pTriInfos.offset((t + 1i32) as isize)).iFlag |= 2i32 - } - t += 2i32 - } else { - t += 1 - } - } - iNextGoodTriangleSearchIndex = 1i32; - t = 0i32; - bStillFindingGoodOnes = true; - while t < iNrTrianglesIn && bStillFindingGoodOnes { - let bIsGood: bool = if (*pTriInfos.offset(t as isize)).iFlag & 1i32 == 0i32 { - true - } else { - false - }; - if bIsGood { - if iNextGoodTriangleSearchIndex < t + 2i32 { - iNextGoodTriangleSearchIndex = t + 2i32 - } - } else { - let mut t0: i32 = 0; - let mut t1: i32 = 0; - let mut bJustADegenerate: bool = true; - while bJustADegenerate && iNextGoodTriangleSearchIndex < iTotTris { - let bIsGood_0: bool = - if (*pTriInfos.offset(iNextGoodTriangleSearchIndex as isize)).iFlag & 1i32 - == 0i32 - { - true - } else { - false - }; - if bIsGood_0 { - bJustADegenerate = false - } else { - iNextGoodTriangleSearchIndex += 1 - } - } - t0 = t; - t1 = iNextGoodTriangleSearchIndex; - iNextGoodTriangleSearchIndex += 1; - if !bJustADegenerate { - let mut i: i32 = 0i32; - i = 0i32; - while i < 3i32 { - let index: i32 = *piTriList_out.offset((t0 * 3i32 + i) as isize); - *piTriList_out.offset((t0 * 3i32 + i) as isize) = - *piTriList_out.offset((t1 * 3i32 + i) as isize); - *piTriList_out.offset((t1 * 3i32 + i) as isize) = index; - i += 1 - } - let tri_info: STriInfo = *pTriInfos.offset(t0 as isize); - *pTriInfos.offset(t0 as isize) = *pTriInfos.offset(t1 as isize); - *pTriInfos.offset(t1 as isize) = tri_info - } else { - bStillFindingGoodOnes = false - } - } - if bStillFindingGoodOnes { - t += 1 - } - } -} -unsafe fn GenerateSharedVerticesIndexList( - mut piTriList_in_and_out: *mut i32, - geometry: &mut I, - iNrTrianglesIn: usize, -) { - let mut i = 0; - let mut iChannel: i32 = 0i32; - let mut k = 0; - let mut e = 0; - let mut iMaxCount = 0; - let mut vMin = get_position(geometry, 0); - let mut vMax = vMin; - let mut vDim = Vec3::new(0.0, 0.0, 0.0); - let mut fMin: f32 = 0.; - let mut fMax: f32 = 0.; - i = 1; - while i < iNrTrianglesIn * 3 { - let index: i32 = *piTriList_in_and_out.offset(i as isize); - let vP = get_position(geometry, index as usize); - if vMin.x > vP.x { - vMin.x = vP.x - } else if vMax.x < vP.x { - vMax.x = vP.x - } - if vMin.y > vP.y { - vMin.y = vP.y - } else if vMax.y < vP.y { - vMax.y = vP.y - } - if vMin.z > vP.z { - vMin.z = vP.z - } else if vMax.z < vP.z { - vMax.z = vP.z - } - i += 1 - } - vDim = vMax - vMin; - iChannel = 0i32; - fMin = vMin.x; - fMax = vMax.x; - if vDim.y > vDim.x && vDim.y > vDim.z { - iChannel = 1i32; - fMin = vMin.y; - fMax = vMax.y - } else if vDim.z > vDim.x { - iChannel = 2i32; - fMin = vMin.z; - fMax = vMax.z - } - - let mut piHashTable = vec![0i32; iNrTrianglesIn * 3]; - let mut piHashOffsets = vec![0i32; g_iCells]; - let mut piHashCount = vec![0i32; g_iCells]; - let mut piHashCount2 = vec![0i32; g_iCells]; - - i = 0; - while i < iNrTrianglesIn * 3 { - let index_0: i32 = *piTriList_in_and_out.offset(i as isize); - let vP_0 = get_position(geometry, index_0 as usize); - let fVal: f32 = if iChannel == 0i32 { - vP_0.x - } else if iChannel == 1i32 { - vP_0.y - } else { - vP_0.z - }; - let iCell = FindGridCell(fMin, fMax, fVal); - piHashCount[iCell] += 1; - i += 1 - } - piHashOffsets[0] = 0i32; - k = 1; - while k < g_iCells { - piHashOffsets[k] = piHashOffsets[k - 1] + piHashCount[k - 1]; - k += 1 - } - i = 0; - while i < iNrTrianglesIn * 3 { - let index_1: i32 = *piTriList_in_and_out.offset(i as isize); - let vP_1 = get_position(geometry, index_1 as usize); - let fVal_0: f32 = if iChannel == 0i32 { - vP_1.x - } else if iChannel == 1i32 { - vP_1.y - } else { - vP_1.z - }; - let iCell_0 = FindGridCell(fMin, fMax, fVal_0); - piHashTable[(piHashOffsets[iCell_0] + piHashCount2[iCell_0]) as usize] = i as i32; - piHashCount2[iCell_0] += 1; - i += 1 - } - k = 0; - while k < g_iCells { - k += 1 - } - iMaxCount = piHashCount[0] as usize; - k = 1; - while k < g_iCells { - if iMaxCount < piHashCount[k] as usize { - iMaxCount = piHashCount[k] as usize - } - k += 1 - } - let mut pTmpVert = vec![STmpVert::zero(); iMaxCount]; - k = 0; - while k < g_iCells { - // extract table of cell k and amount of entries in it - let pTable_0 = piHashTable.as_mut_ptr().offset(piHashOffsets[k] as isize); - let iEntries = piHashCount[k] as usize; - if !(iEntries < 2) { - e = 0; - while e < iEntries { - let mut i_0: i32 = *pTable_0.offset(e as isize); - let vP_2 = get_position( - geometry, - *piTriList_in_and_out.offset(i_0 as isize) as usize, - ); - pTmpVert[e].vert[0usize] = vP_2.x; - pTmpVert[e].vert[1usize] = vP_2.y; - pTmpVert[e].vert[2usize] = vP_2.z; - pTmpVert[e].index = i_0; - e += 1 - } - MergeVertsFast( - piTriList_in_and_out, - pTmpVert.as_mut_ptr(), - geometry, - 0i32, - (iEntries - 1) as i32, - ); - } - k += 1 - } -} - -unsafe fn MergeVertsFast( - mut piTriList_in_and_out: *mut i32, - mut pTmpVert: *mut STmpVert, - geometry: &mut I, - iL_in: i32, - iR_in: i32, -) { - // make bbox - let mut c: i32 = 0i32; - let mut l: i32 = 0i32; - let mut channel: i32 = 0i32; - let mut fvMin: [f32; 3] = [0.; 3]; - let mut fvMax: [f32; 3] = [0.; 3]; - let mut dx: f32 = 0i32 as f32; - let mut dy: f32 = 0i32 as f32; - let mut dz: f32 = 0i32 as f32; - let mut fSep: f32 = 0i32 as f32; - c = 0i32; - while c < 3i32 { - fvMin[c as usize] = (*pTmpVert.offset(iL_in as isize)).vert[c as usize]; - fvMax[c as usize] = fvMin[c as usize]; - c += 1 - } - l = iL_in + 1i32; - while l <= iR_in { - c = 0i32; - while c < 3i32 { - if fvMin[c as usize] > (*pTmpVert.offset(l as isize)).vert[c as usize] { - fvMin[c as usize] = (*pTmpVert.offset(l as isize)).vert[c as usize] - } else if fvMax[c as usize] < (*pTmpVert.offset(l as isize)).vert[c as usize] { - fvMax[c as usize] = (*pTmpVert.offset(l as isize)).vert[c as usize] - } - c += 1 - } - l += 1 - } - dx = fvMax[0usize] - fvMin[0usize]; - dy = fvMax[1usize] - fvMin[1usize]; - dz = fvMax[2usize] - fvMin[2usize]; - channel = 0i32; - if dy > dx && dy > dz { - channel = 1i32 - } else if dz > dx { - channel = 2i32 - } - fSep = 0.5f32 * (fvMax[channel as usize] + fvMin[channel as usize]); - if fSep >= fvMax[channel as usize] || fSep <= fvMin[channel as usize] { - l = iL_in; - while l <= iR_in { - let mut i: i32 = (*pTmpVert.offset(l as isize)).index; - let index: i32 = *piTriList_in_and_out.offset(i as isize); - let vP = get_position(geometry, index as usize); - let vN = get_normal(geometry, index as usize); - let vT = get_tex_coord(geometry, index as usize); - let mut bNotFound: bool = true; - let mut l2: i32 = iL_in; - let mut i2rec: i32 = -1i32; - while l2 < l && bNotFound { - let i2: i32 = (*pTmpVert.offset(l2 as isize)).index; - let index2: i32 = *piTriList_in_and_out.offset(i2 as isize); - let vP2 = get_position(geometry, index2 as usize); - let vN2 = get_normal(geometry, index2 as usize); - let vT2 = get_tex_coord(geometry, index2 as usize); - i2rec = i2; - if vP.x == vP2.x - && vP.y == vP2.y - && vP.z == vP2.z - && vN.x == vN2.x - && vN.y == vN2.y - && vN.z == vN2.z - && vT.x == vT2.x - && vT.y == vT2.y - && vT.z == vT2.z - { - bNotFound = false - } else { - l2 += 1 - } - } - if !bNotFound { - *piTriList_in_and_out.offset(i as isize) = - *piTriList_in_and_out.offset(i2rec as isize) - } - l += 1 - } - } else { - let mut iL: i32 = iL_in; - let mut iR: i32 = iR_in; - while iL < iR { - let mut bReadyLeftSwap: bool = false; - let mut bReadyRightSwap: bool = false; - while !bReadyLeftSwap && iL < iR { - bReadyLeftSwap = !((*pTmpVert.offset(iL as isize)).vert[channel as usize] < fSep); - if !bReadyLeftSwap { - iL += 1 - } - } - while !bReadyRightSwap && iL < iR { - bReadyRightSwap = (*pTmpVert.offset(iR as isize)).vert[channel as usize] < fSep; - if !bReadyRightSwap { - iR -= 1 - } - } - if bReadyLeftSwap && bReadyRightSwap { - let sTmp: STmpVert = *pTmpVert.offset(iL as isize); - *pTmpVert.offset(iL as isize) = *pTmpVert.offset(iR as isize); - *pTmpVert.offset(iR as isize) = sTmp; - iL += 1; - iR -= 1 - } - } - if iL == iR { - let bReadyRightSwap_0: bool = - (*pTmpVert.offset(iR as isize)).vert[channel as usize] < fSep; - if bReadyRightSwap_0 { - iL += 1 - } else { - iR -= 1 - } - } - if iL_in < iR { - MergeVertsFast(piTriList_in_and_out, pTmpVert, geometry, iL_in, iR); - } - if iL < iR_in { - MergeVertsFast(piTriList_in_and_out, pTmpVert, geometry, iL, iR_in); - } - }; -} - -const g_iCells: usize = 2048; - -// it is IMPORTANT that this function is called to evaluate the hash since -// inlining could potentially reorder instructions and generate different -// results for the same effective input value fVal. -#[inline(never)] -unsafe fn FindGridCell(fMin: f32, fMax: f32, fVal: f32) -> usize { - let fIndex = g_iCells as f32 * ((fVal - fMin) / (fMax - fMin)); - let iIndex = fIndex as isize; - return if iIndex < g_iCells as isize { - if iIndex >= 0 { - iIndex as usize - } else { - 0 - } - } else { - g_iCells - 1 - }; -} - -unsafe fn GenerateInitialVerticesIndexList( - pTriInfos: &mut [STriInfo], - piTriList_out: &mut [i32], - geometry: &mut I, - iNrTrianglesIn: usize, -) -> usize { - let mut iTSpacesOffs: usize = 0; - let mut f = 0; - let mut t: usize = 0; - let mut iDstTriIndex = 0; - f = 0; - while f < geometry.num_faces() { - let verts = geometry.num_vertices_of_face(f); - if !(verts != 3 && verts != 4) { - pTriInfos[iDstTriIndex].iOrgFaceNumber = f as i32; - pTriInfos[iDstTriIndex].iTSpacesOffs = iTSpacesOffs as i32; - if verts == 3 { - let mut pVerts = &mut pTriInfos[iDstTriIndex].vert_num; - pVerts[0] = 0; - pVerts[1] = 1; - pVerts[2] = 2; - piTriList_out[iDstTriIndex * 3 + 0] = face_vert_to_index(f, 0) as i32; - piTriList_out[iDstTriIndex * 3 + 1] = face_vert_to_index(f, 1) as i32; - piTriList_out[iDstTriIndex * 3 + 2] = face_vert_to_index(f, 2) as i32; - iDstTriIndex += 1 - } else { - pTriInfos[iDstTriIndex + 1].iOrgFaceNumber = f as i32; - pTriInfos[iDstTriIndex + 1].iTSpacesOffs = iTSpacesOffs as i32; - let i0 = face_vert_to_index(f, 0); - let i1 = face_vert_to_index(f, 1); - let i2 = face_vert_to_index(f, 2); - let i3 = face_vert_to_index(f, 3); - let T0 = get_tex_coord(geometry, i0); - let T1 = get_tex_coord(geometry, i1); - let T2 = get_tex_coord(geometry, i2); - let T3 = get_tex_coord(geometry, i3); - let distSQ_02: f32 = (T2 - T0).length_squared(); - let distSQ_13: f32 = (T3 - T1).length_squared(); - let mut bQuadDiagIs_02: bool = false; - if distSQ_02 < distSQ_13 { - bQuadDiagIs_02 = true - } else if distSQ_13 < distSQ_02 { - bQuadDiagIs_02 = false - } else { - let P0 = get_position(geometry, i0); - let P1 = get_position(geometry, i1); - let P2 = get_position(geometry, i2); - let P3 = get_position(geometry, i3); - let distSQ_02_0: f32 = (P2 - P0).length_squared(); - let distSQ_13_0: f32 = (P3 - P1).length_squared(); - bQuadDiagIs_02 = if distSQ_13_0 < distSQ_02_0 { - false - } else { - true - } - } - if bQuadDiagIs_02 { - let mut pVerts_A = &mut pTriInfos[iDstTriIndex].vert_num; - pVerts_A[0] = 0; - pVerts_A[1] = 1; - pVerts_A[2] = 2; - piTriList_out[iDstTriIndex * 3 + 0] = i0 as i32; - piTriList_out[iDstTriIndex * 3 + 1] = i1 as i32; - piTriList_out[iDstTriIndex * 3 + 2] = i2 as i32; - iDstTriIndex += 1; - - let mut pVerts_B = &mut pTriInfos[iDstTriIndex].vert_num; - pVerts_B[0] = 0; - pVerts_B[1] = 2; - pVerts_B[2] = 3; - piTriList_out[iDstTriIndex * 3 + 0] = i0 as i32; - piTriList_out[iDstTriIndex * 3 + 1] = i2 as i32; - piTriList_out[iDstTriIndex * 3 + 2] = i3 as i32; - iDstTriIndex += 1 - } else { - let mut pVerts_A_0 = &mut pTriInfos[iDstTriIndex].vert_num; - pVerts_A_0[0] = 0; - pVerts_A_0[1] = 1; - pVerts_A_0[2] = 3; - piTriList_out[iDstTriIndex * 3 + 0] = i0 as i32; - piTriList_out[iDstTriIndex * 3 + 1] = i1 as i32; - piTriList_out[iDstTriIndex * 3 + 2] = i3 as i32; - iDstTriIndex += 1; - - let mut pVerts_B_0 = &mut pTriInfos[iDstTriIndex].vert_num; - pVerts_B_0[0] = 1; - pVerts_B_0[1] = 2; - pVerts_B_0[2] = 3; - piTriList_out[iDstTriIndex * 3 + 0] = i1 as i32; - piTriList_out[iDstTriIndex * 3 + 1] = i2 as i32; - piTriList_out[iDstTriIndex * 3 + 2] = i3 as i32; - iDstTriIndex += 1 - } - } - iTSpacesOffs += verts - } - f += 1 - } - t = 0; - while t < iNrTrianglesIn { - pTriInfos[t].iFlag = 0; - t += 1 - } - return iTSpacesOffs; -} diff --git a/crates/bevy_mikktspace/src/geometry.rs b/crates/bevy_mikktspace/src/geometry.rs new file mode 100644 index 0000000000000..41ce7e5ef4e5d --- /dev/null +++ b/crates/bevy_mikktspace/src/geometry.rs @@ -0,0 +1,45 @@ +/// Interface for the mikktspace algorithm to query information about your geometry. +pub trait Geometry { + /// Returns the number of faces. + fn num_faces(&self) -> usize; + + /// Returns the number of vertices of a face. + fn num_vertices_of_face(&self, face: usize) -> usize; + + /// Returns the position of a vertex. + fn position(&self, face: usize, vert: usize) -> [f32; 3]; + + /// Returns the normal of a vertex. + fn normal(&self, face: usize, vert: usize) -> [f32; 3]; + + /// Returns the texture coordinate of a vertex. + fn tex_coord(&self, face: usize, vert: usize) -> [f32; 2]; + + /// Sets the generated tangent for a vertex. + /// Leave this function unimplemented if you are implementing + /// `set_tangent_encoded`. + #[allow(clippy::too_many_arguments)] + fn set_tangent( + &mut self, + tangent: [f32; 3], + _bi_tangent: [f32; 3], + _f_mag_s: f32, + _f_mag_t: f32, + bi_tangent_preserves_orientation: bool, + face: usize, + vert: usize, + ) { + let sign = if bi_tangent_preserves_orientation { + 1.0 + } else { + -1.0 + }; + self.set_tangent_encoded([tangent[0], tangent[1], tangent[2], sign], face, vert); + } + + /// Sets the generated tangent for a vertex with its bi-tangent encoded as the 'W' (4th) + /// component in the tangent. The 'W' component marks if the bi-tangent is flipped. This + /// is called by the default implementation of `set_tangent`; therefore, this function will + /// not be called by the crate unless `set_tangent` is unimplemented. + fn set_tangent_encoded(&mut self, _tangent: [f32; 4], _face: usize, _vert: usize) {} +} diff --git a/crates/bevy_mikktspace/src/lib.rs b/crates/bevy_mikktspace/src/lib.rs index 365c2734800db..7d766726660db 100644 --- a/crates/bevy_mikktspace/src/lib.rs +++ b/crates/bevy_mikktspace/src/lib.rs @@ -1,54 +1,36 @@ -#![allow(clippy::type_complexity)] -#![allow(clippy::all)] +//! Mikktspace ported to *safe* Rust. +//! +//! This library is based on Morten S. Mikkelsen's original tangent space algorithm +//! implementation, written in C. The original source code can be found at +//! +//! and includes the following licence: +//! +//! > Copyright (C) 2011 by Morten S. Mikkelsen +//! > +//! > This software is provided 'as-is', without any express or implied +//! > warranty. In no event will the authors be held liable for any damages +//! > arising from the use of this software. +//! > +//! > Permission is granted to anyone to use this software for any purpose, +//! > including commercial applications, and to alter it and redistribute it +//! > freely, subject to the following restrictions: +//! > +//! > 1. The origin of this software must not be misrepresented; you must not +//! > claim that you wrote the original software. If you use this software +//! > in a product, an acknowledgment in the product documentation would be +//! > appreciated but is not required. +//! > +//! > 2. Altered source versions must be plainly marked as such, and must not be +//! > misrepresented as being the original software. +//! > +//! > 3. This notice may not be removed or altered from any source distribution. +use bitflags::bitflags; use glam::{Vec2, Vec3}; -mod generated; - -/// The interface by which mikktspace interacts with your geometry. -pub trait Geometry { - /// Returns the number of faces. - fn num_faces(&self) -> usize; - - /// Returns the number of vertices of a face. - fn num_vertices_of_face(&self, face: usize) -> usize; - - /// Returns the position of a vertex. - fn position(&self, face: usize, vert: usize) -> [f32; 3]; - - /// Returns the normal of a vertex. - fn normal(&self, face: usize, vert: usize) -> [f32; 3]; - - /// Returns the texture coordinate of a vertex. - fn tex_coord(&self, face: usize, vert: usize) -> [f32; 2]; - - /// Sets the generated tangent for a vertex. - /// Leave this function unimplemented if you are implementing - /// `set_tangent_encoded`. - fn set_tangent( - &mut self, - tangent: [f32; 3], - _bi_tangent: [f32; 3], - _f_mag_s: f32, - _f_mag_t: f32, - bi_tangent_preserves_orientation: bool, - face: usize, - vert: usize, - ) { - let sign = if bi_tangent_preserves_orientation { - 1.0 - } else { - -1.0 - }; - self.set_tangent_encoded([tangent[0], tangent[1], tangent[2], sign], face, vert); - } +mod geometry; - /// Sets the generated tangent for a vertex with its bi-tangent encoded as the 'W' (4th) - /// component in the tangent. The 'W' component marks if the bi-tangent is flipped. This - /// is called by the default implementation of `set_tangent`; therefore, this function will - /// not be called by the crate unless `set_tangent` is unimplemented. - fn set_tangent_encoded(&mut self, _tangent: [f32; 4], _face: usize, _vert: usize) {} -} +pub use geometry::Geometry; /// Generates tangents for the input geometry. /// @@ -56,31 +38,1712 @@ pub trait Geometry { /// /// Returns `false` if the geometry is unsuitable for tangent generation including, /// but not limited to, lack of vertices. -pub fn generate_tangents(geometry: &mut I) -> bool { - unsafe { generated::genTangSpace(geometry, 180.0) } +pub fn generate_tangents(geometry: &mut G) -> bool { + generate_tangents_with(geometry, 180.0) +} + +fn generate_tangents_with(geometry: &mut G, angular_threshold: f32) -> bool { + // count triangles on supported faces + let mut triangles_count = 0; + for face in 0..geometry.num_faces() { + let verts = geometry.num_vertices_of_face(face); + if verts == 3 { + triangles_count += 1; + } else if verts == 4 { + triangles_count += 2; + } + } + + // make an initial triangle --> face index list + let (mut triangles_info, mut vertex_indices, tspaces_count) = + generate_initial_vertex_indices(geometry, triangles_count); + + // make a welded index list of identical positions and attributes (pos, norm, texc) + generate_shared_vertices_index_list(&mut vertex_indices, geometry, triangles_count); + + // Mark all degenerate triangles + let total_triangles_count = triangles_count; + let mut degen_triangles_count = 0; + for triangle in 0..total_triangles_count { + let i0 = vertex_indices[triangle * 3]; + let i1 = vertex_indices[triangle * 3 + 1]; + let i2 = vertex_indices[triangle * 3 + 2]; + let p0 = get_position(geometry, i0 as usize); + let p1 = get_position(geometry, i1 as usize); + let p2 = get_position(geometry, i2 as usize); + + if p0 == p1 || p0 == p2 || p1 == p2 { + triangles_info[triangle] + .flags + .set(TriangleFlags::MARK_DEGENERATE, true); + degen_triangles_count += 1; + } + } + triangles_count = total_triangles_count - degen_triangles_count; + + // mark all triangle pairs that belong to a quad with only one + // good triangle. These need special treatment in DegenEpilogue(). + // Additionally, move all good triangles to the start of + // pTriInfos[] and piTriListIn[] without changing order and + // put the degenerate triangles last. + degen_prologue( + &mut triangles_info, + &mut vertex_indices, + triangles_count as i32, + total_triangles_count as i32, + ); + + // evaluate triangle level attributes and neighbor list + init_tri_info( + geometry, + &mut triangles_info, + &vertex_indices, + triangles_count, + ); + + // based on the 4 rules, identify groups based on connectivity + let max_groups = triangles_count * 3; + let mut groups = vec![Group::zero(); max_groups]; + let mut face_indices_buffer = vec![0; triangles_count * 3]; + + let active_groups = build_4_rule_groups( + &mut triangles_info, + &mut groups, + &mut face_indices_buffer, + &vertex_indices, + triangles_count as i32, + ); + + let mut tspaces = vec![ + TSpace { + os: Vec3::new(1.0, 0.0, 0.0), + mag_s: 1.0, + ot: Vec3::new(0.0, 1.0, 0.0), + mag_t: 1.0, + ..TSpace::zero() + }; + tspaces_count as usize + ]; + + // make tspaces, each group is split up into subgroups if necessary + // based on fAngularThreshold. Finally a tangent space is made for + // every resulting subgroup + let thres_cos = (angular_threshold * std::f32::consts::PI / 180.0).cos(); + generate_tspaces( + geometry, + &mut tspaces, + &triangles_info, + &mut groups, + active_groups, + &vertex_indices, + thres_cos, + &face_indices_buffer, + ); + + // degenerate quads with one good triangle will be fixed by copying a space from + // the good triangle to the coinciding vertex. + // all other degenerate triangles will just copy a space from any good triangle + // with the same welded index in piTriListIn[]. + degen_epilogue( + geometry, + &mut tspaces, + &mut triangles_info, + &vertex_indices, + triangles_count as i32, + total_triangles_count as i32, + ); + + let mut index = 0; + for face in 0..geometry.num_faces() { + let verts_0 = geometry.num_vertices_of_face(face); + if !(verts_0 != 3 && verts_0 != 4) { + // I've decided to let degenerate triangles and group-with-anythings + // vary between left/right hand coordinate systems at the vertices. + // All healthy triangles on the other hand are built to always be either or. + + // set data + for i in 0..verts_0 { + let tspace = &tspaces[index]; + let tang = Vec3::new(tspace.os.x, tspace.os.y, tspace.os.z); + let bitang = Vec3::new(tspace.ot.x, tspace.ot.y, tspace.ot.z); + geometry.set_tangent( + tang.into(), + bitang.into(), + tspace.mag_s, + tspace.mag_t, + tspace.orient, + face, + i, + ); + index += 1; + } + } + } + + true +} + +#[derive(Copy, Clone)] +struct TriangleInfo { + face_neighbors: [i32; 3], + assigned_group: [usize; 3], + os: Vec3, + ot: Vec3, + mag_s: f32, + mag_t: f32, + /// Index of the face this triangle maps to, in the original faces. + original_face_index: i32, + flags: TriangleFlags, + /// Offset of the first vertex of this triangle, in the original vertices. + vertex_offset: i32, + /// Offsets of the vertices of this triangle, relative to the triangle index, last always 0. + vertex_indices: [u8; 4], +} + +bitflags! { + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] + struct TriangleFlags: u32 { + const MARK_DEGENERATE = 0b00000001; + const QUAD_ONE_DEGEN_TRI = 0b00000010; + const GROUP_WITH_ANY = 0b00000100; + const ORIENT_PRESERVING = 0b00001000; + } +} + +impl TriangleInfo { + fn zero() -> Self { + Self { + face_neighbors: [0, 0, 0], + assigned_group: [usize::MAX, usize::MAX, usize::MAX], + os: Default::default(), + ot: Default::default(), + mag_s: 0.0, + mag_t: 0.0, + original_face_index: 0, + flags: TriangleFlags::empty(), + vertex_offset: 0, + vertex_indices: [0, 0, 0, 0], + } + } +} + +/// Generate initial triangles and vertex indices, from original geometry. +fn generate_initial_vertex_indices( + geometry: &mut G, + triangles_count: usize, +) -> (Vec, Vec, i32) { + let mut triangles_info = vec![TriangleInfo::zero(); triangles_count]; + let mut vertex_indices = vec![0i32; 3 * triangles_count]; + + let mut vertex_offset = 0; + let mut triangle_index = 0; + + for face_index in 0..geometry.num_faces() { + let face_vertices_count = geometry.num_vertices_of_face(face_index); + + // Only generate for tris or quads + if face_vertices_count != 3 && face_vertices_count != 4 { + continue; + } + + triangles_info[triangle_index].original_face_index = face_index as i32; + triangles_info[triangle_index].vertex_offset = vertex_offset; + + if face_vertices_count == 3 { + // For tris + + triangles_info[triangle_index].vertex_indices = [0, 1, 2, 0]; + vertex_indices[triangle_index * 3] = face_vertex_to_index(face_index, 0) as i32; + vertex_indices[triangle_index * 3 + 1] = face_vertex_to_index(face_index, 1) as i32; + vertex_indices[triangle_index * 3 + 2] = face_vertex_to_index(face_index, 2) as i32; + + triangle_index += 1; + } else { + // For quads + + triangles_info[triangle_index + 1].original_face_index = face_index as i32; + triangles_info[triangle_index + 1].vertex_offset = vertex_offset; + + let i0 = face_vertex_to_index(face_index, 0); + let i1 = face_vertex_to_index(face_index, 1); + let i2 = face_vertex_to_index(face_index, 2); + let i3 = face_vertex_to_index(face_index, 3); + + // Figure out the best cut for the quad + let t0 = get_tex_coord(geometry, i0); + let t1 = get_tex_coord(geometry, i1); + let t2 = get_tex_coord(geometry, i2); + let t3 = get_tex_coord(geometry, i3); + let length_squared_02: f32 = (t2 - t0).length_squared(); + let length_squared_13: f32 = (t3 - t1).length_squared(); + let quad_diagonal_is_02; + + if length_squared_02 < length_squared_13 { + quad_diagonal_is_02 = true; + } else if length_squared_13 < length_squared_02 { + quad_diagonal_is_02 = false; + } else { + let p0 = get_position(geometry, i0); + let p1 = get_position(geometry, i1); + let p2 = get_position(geometry, i2); + let p3 = get_position(geometry, i3); + let length_squared_02_0: f32 = (p2 - p0).length_squared(); + let length_squared_13_0: f32 = (p3 - p1).length_squared(); + quad_diagonal_is_02 = length_squared_13_0 >= length_squared_02_0; + } + + // Apply indices for the cut we determined + if quad_diagonal_is_02 { + triangles_info[triangle_index].vertex_indices = [0, 1, 2, 0]; + vertex_indices[triangle_index * 3] = i0 as i32; + vertex_indices[triangle_index * 3 + 1] = i1 as i32; + vertex_indices[triangle_index * 3 + 2] = i2 as i32; + triangle_index += 1; + + triangles_info[triangle_index].vertex_indices = [0, 2, 3, 0]; + vertex_indices[triangle_index * 3] = i0 as i32; + vertex_indices[triangle_index * 3 + 1] = i2 as i32; + vertex_indices[triangle_index * 3 + 2] = i3 as i32; + triangle_index += 1; + } else { + triangles_info[triangle_index].vertex_indices = [0, 1, 3, 0]; + vertex_indices[triangle_index * 3] = i0 as i32; + vertex_indices[triangle_index * 3 + 1] = i1 as i32; + vertex_indices[triangle_index * 3 + 2] = i3 as i32; + triangle_index += 1; + + triangles_info[triangle_index].vertex_indices = [1, 2, 3, 0]; + vertex_indices[triangle_index * 3] = i1 as i32; + vertex_indices[triangle_index * 3 + 1] = i2 as i32; + vertex_indices[triangle_index * 3 + 2] = i3 as i32; + triangle_index += 1; + } + } + + vertex_offset += face_vertices_count as i32; + } + + for face_info in &mut triangles_info { + face_info.flags = TriangleFlags::empty(); + } + + (triangles_info, vertex_indices, vertex_offset) +} + +// Mikktspace uses indices internally to refer to and identify vertices, these utility functions +// make it easier to work with these indices. + +/// Generate a vertex index for the Nth vertex of the Nth face. +fn face_vertex_to_index(face_index: usize, vertex: usize) -> usize { + face_index << 2 | vertex & 0x3 +} + +/// Reverse of `face_vertex_to_index`. +fn index_to_face_vertex(index: usize) -> (usize, usize) { + (index >> 2, index & 0x3) } -fn get_position(geometry: &mut I, index: usize) -> Vec3 { - let (face, vert) = index_to_face_vert(index); +fn get_position(geometry: &mut G, index: usize) -> Vec3 { + let (face, vert) = index_to_face_vertex(index); geometry.position(face, vert).into() } -fn get_tex_coord(geometry: &mut I, index: usize) -> Vec3 { - let (face, vert) = index_to_face_vert(index); +fn get_tex_coord(geometry: &mut G, index: usize) -> Vec3 { + let (face, vert) = index_to_face_vertex(index); let tex_coord: Vec2 = geometry.tex_coord(face, vert).into(); - let val = tex_coord.extend(1.0); - val + tex_coord.extend(1.0) } -fn get_normal(geometry: &mut I, index: usize) -> Vec3 { - let (face, vert) = index_to_face_vert(index); +fn get_normal(geometry: &mut G, index: usize) -> Vec3 { + let (face, vert) = index_to_face_vertex(index); geometry.normal(face, vert).into() } -fn index_to_face_vert(index: usize) -> (usize, usize) { - (index >> 2, index & 0x3) +#[derive(Copy, Clone)] +struct TSpace { + os: Vec3, + mag_s: f32, + ot: Vec3, + mag_t: f32, + counter: i32, + orient: bool, +} + +impl TSpace { + fn zero() -> Self { + Self { + os: Default::default(), + mag_s: 0.0, + ot: Default::default(), + mag_t: 0.0, + counter: 0, + orient: false, + } + } +} + +// To avoid visual errors (distortions/unwanted hard edges in lighting), when using sampled normal +// maps, the normal map sampler must use the exact inverse of the pixel shader transformation. +// The most efficient transformation we can possibly do in the pixel shader is +// achieved by using, directly, the "unnormalized" interpolated tangent, bitangent and vertex +// normal: vT, vB and vN. +// pixel shader (fast transform out) +// vNout = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN ); +// where vNt is the tangent space normal. The normal map sampler must likewise use the +// interpolated and "unnormalized" tangent, bitangent and vertex normal to be compliant with the +// pixel shader. +// sampler does (exact inverse of pixel shader): +// float3 row0 = cross(vB, vN); +// float3 row1 = cross(vN, vT); +// float3 row2 = cross(vT, vB); +// float fSign = dot(vT, row0)<0 ? -1 : 1; +// vNt = normalize( fSign * float3(dot(vNout,row0), dot(vNout,row1), dot(vNout,row2)) ); +// where vNout is the sampled normal in some chosen 3D space. +// +// Should you choose to reconstruct the bitangent in the pixel shader instead +// of the vertex shader, as explained earlier, then be sure to do this in the normal map sampler +// also. +// Finally, beware of quad triangulations. If the normal map sampler doesn't use the same +// triangulation of +// quads as your renderer then problems will occur since the interpolated tangent spaces will differ +// eventhough the vertex level tangent spaces match. This can be solved either by triangulating +// before +// sampling/exporting or by using the order-independent choice of diagonal for splitting quads +// suggested earlier. +// However, this must be used both by the sampler and your tools/rendering pipeline. +// internal structure + +#[derive(Copy, Clone)] +struct Group { + face_indices_len: usize, + /// Index of the first face index in the buffer. + face_indices_index: usize, + vertex_representative: i32, + orient_preservering: bool, +} + +impl Group { + fn zero() -> Self { + Self { + face_indices_len: 0, + face_indices_index: usize::MAX, + vertex_representative: 0, + orient_preservering: false, + } + } +} + +#[derive(Clone)] +struct SubGroup { + faces_count: i32, + tri_members: Vec, +} + +impl SubGroup { + fn zero() -> Self { + Self { + faces_count: 0, + tri_members: Vec::new(), + } + } +} + +#[derive(Copy, Clone)] +struct Edge { + i0: i32, + i1: i32, + f: i32, +} + +impl Edge { + fn zero() -> Self { + Self { i0: 0, i1: 0, f: 0 } + } + + fn channel(&self, i: i32) -> i32 { + [self.i0, self.i1, self.f][i as usize] + } +} + +#[derive(Copy, Clone)] +struct TmpVert { + vert: [f32; 3], + index: i32, +} + +impl TmpVert { + fn zero() -> Self { + Self { + vert: [0.0, 0.0, 0.0], + index: 0, + } + } +} + +fn degen_epilogue( + geometry: &mut G, + tspaces: &mut [TSpace], + triangles_info: &mut [TriangleInfo], + vertex_indices: &[i32], + triangles_count: i32, + total_triangles_count: i32, +) { + // deal with degenerate triangles + // punishment for degenerate triangles is O(N^2) + for t in triangles_count..total_triangles_count { + // degenerate triangles on a quad with one good triangle are skipped + // here but processed in the next loop + let skip = triangles_info[t as usize] + .flags + .contains(TriangleFlags::QUAD_ONE_DEGEN_TRI); + + if !skip { + for i in 0..3 { + let index1: i32 = vertex_indices[(t * 3i32 + i) as usize]; + let mut not_found: bool = true; + let mut j: i32 = 0i32; + while not_found && j < 3i32 * triangles_count { + let index2: i32 = vertex_indices[j as usize]; + if index1 == index2 { + not_found = false; + } else { + j += 1; + } + } + if !not_found { + let tri: i32 = j / 3i32; + let vert: i32 = j % 3i32; + let src_vert: i32 = + triangles_info[tri as usize].vertex_indices[vert as usize] as i32; + let src_offs: i32 = triangles_info[tri as usize].vertex_offset; + let dst_vert: i32 = + triangles_info[t as usize].vertex_indices[i as usize] as i32; + let dst_offs: i32 = triangles_info[t as usize].vertex_offset; + tspaces[(dst_offs + dst_vert) as usize] = + tspaces[(src_offs + src_vert) as usize]; + } + } + } + } + + // deal with degenerate quads with one good triangle + for t in 0..triangles_count { + // this triangle belongs to a quad where the + // other triangle is degenerate + if triangles_info[t as usize] + .flags + .contains(TriangleFlags::QUAD_ONE_DEGEN_TRI) + { + let pv = triangles_info[t as usize].vertex_indices; + let flag = (1 << pv[0]) | (1 << pv[1]) | (1 << pv[2]); + let mut missing_index: i32 = 0i32; + if flag & 2i32 == 0i32 { + missing_index = 1i32; + } else if flag & 4i32 == 0i32 { + missing_index = 2i32; + } else if flag & 8i32 == 0i32 { + missing_index = 3i32; + } + let org_f = triangles_info[t as usize].original_face_index; + let v_dst_p = get_position( + geometry, + face_vertex_to_index(org_f as usize, missing_index as usize), + ); + + let mut not_found = true; + let mut i_0 = 0i32; + while not_found && i_0 < 3i32 { + let vert: i32 = pv[i_0 as usize] as i32; + let v_src_p = get_position( + geometry, + face_vertex_to_index(org_f as usize, vert as usize), + ); + if v_src_p == v_dst_p { + let offs: i32 = triangles_info[t as usize].vertex_offset; + tspaces[(offs + missing_index) as usize] = tspaces[(offs + vert) as usize]; + not_found = false; + } else { + i_0 += 1; + } + } + } + } +} + +#[allow(clippy::too_many_arguments)] +fn generate_tspaces( + geometry: &mut G, + tspaces: &mut [TSpace], + triangles_info: &[TriangleInfo], + groups: &mut [Group], + active_groups: i32, + vertex_indices: &[i32], + thres_cos: f32, + face_indices_buffer: &[i32], +) { + let mut max_faces_count: usize = 0; + for g in 0..active_groups { + if max_faces_count < groups[g as usize].face_indices_len { + max_faces_count = groups[g as usize].face_indices_len; + } + } + if max_faces_count == 0 { + return; + } + + let mut sub_group_tspace = vec![TSpace::zero(); max_faces_count]; + let mut uni_sub_groups = vec![SubGroup::zero(); max_faces_count]; + let mut tmp_members = vec![0i32; max_faces_count]; + + for g in 0..active_groups { + let group = &mut groups[g as usize]; + let mut unique_sub_groups = 0; + for i in 0..group.face_indices_len as i32 { + let offset = group.face_indices_index + i as usize; + let f: i32 = face_indices_buffer[offset]; + + let mut index: i32 = -1i32; + let mut tmp_group: SubGroup = SubGroup { + faces_count: 0, + tri_members: Vec::new(), + }; + if triangles_info[f as usize].assigned_group[0] == g as usize { + index = 0i32; + } else if triangles_info[f as usize].assigned_group[1] == g as usize { + index = 1i32; + } else if triangles_info[f as usize].assigned_group[2] == g as usize { + index = 2i32; + } + let vertex_index = vertex_indices[(f * 3 + index) as usize]; + let n = get_normal(geometry, vertex_index as usize); + let mut v_os = + triangles_info[f as usize].os - (n.dot(triangles_info[f as usize].os) * n); + let mut v_ot = + triangles_info[f as usize].ot - (n.dot(triangles_info[f as usize].ot) * n); + if v_not_zero(v_os) { + v_os = normalize(v_os); + } + if v_not_zero(v_ot) { + v_ot = normalize(v_ot); + } + let of_1 = triangles_info[f as usize].original_face_index; + let mut members = 0; + for j in 0..group.face_indices_len as i32 { + let offset = group.face_indices_index + j as usize; + let t: i32 = face_indices_buffer[offset]; + + let of_2: i32 = triangles_info[t as usize].original_face_index; + let mut v_os2 = + triangles_info[t as usize].os - (n.dot(triangles_info[t as usize].os) * n); + let mut v_ot2 = + triangles_info[t as usize].ot - (n.dot(triangles_info[t as usize].ot) * n); + if v_not_zero(v_os2) { + v_os2 = normalize(v_os2); + } + if v_not_zero(v_ot2) { + v_ot2 = normalize(v_ot2); + } + + let flags = triangles_info[f as usize].flags | triangles_info[t as usize].flags; + let any = flags.contains(TriangleFlags::GROUP_WITH_ANY); + // make sure triangles which belong to the same quad are joined. + let same_org_face: bool = of_1 == of_2; + let cos_s: f32 = v_os.dot(v_os2); + let cos_t: f32 = v_ot.dot(v_ot2); + if any || same_org_face || cos_s > thres_cos && cos_t > thres_cos { + let fresh0 = members; + members += 1; + tmp_members[fresh0] = t; + } + } + if members > 1 { + let seed: u32 = 39871946i32 as u32; + quick_sort(&mut tmp_members, 0i32, (members - 1) as i32, seed); + } + tmp_group.faces_count = members as i32; + tmp_group.tri_members = tmp_members.clone(); + let mut found = false; + let mut l = 0; + while l < unique_sub_groups && !found { + found = compare_sub_groups(&tmp_group, &uni_sub_groups[l]); + if !found { + l += 1; + } + } + if !found { + uni_sub_groups[unique_sub_groups].faces_count = members as i32; + uni_sub_groups[unique_sub_groups].tri_members = tmp_group.tri_members.clone(); + + sub_group_tspace[unique_sub_groups] = eval_tspace( + geometry, + &tmp_group.tri_members, + members as i32, + vertex_indices, + triangles_info, + group.vertex_representative, + ); + unique_sub_groups += 1; + } + let offs = triangles_info[f as usize].vertex_offset as usize; + let vert = triangles_info[f as usize].vertex_indices[index as usize] as usize; + + let tspaces_out = &mut tspaces[offs + vert]; + if tspaces_out.counter == 1i32 { + *tspaces_out = avg_tspace(tspaces_out, &sub_group_tspace[l]); + tspaces_out.counter = 2i32; + tspaces_out.orient = group.orient_preservering; + } else { + *tspaces_out = sub_group_tspace[l]; + tspaces_out.counter = 1i32; + tspaces_out.orient = group.orient_preservering; + } + } + } +} + +fn avg_tspace(tspace0: &TSpace, tspace1: &TSpace) -> TSpace { + let mut ts_res: TSpace = TSpace { + os: Vec3::new(0.0, 0.0, 0.0), + mag_s: 0., + ot: Vec3::new(0.0, 0.0, 0.0), + mag_t: 0., + counter: 0, + orient: false, + }; + if tspace0.mag_s == tspace1.mag_s + && tspace0.mag_t == tspace1.mag_t + && tspace0.os == tspace1.os + && tspace0.ot == tspace1.ot + { + ts_res.mag_s = tspace0.mag_s; + ts_res.mag_t = tspace0.mag_t; + ts_res.os = tspace0.os; + ts_res.ot = tspace0.ot; + } else { + ts_res.mag_s = 0.5f32 * (tspace0.mag_s + tspace1.mag_s); + ts_res.mag_t = 0.5f32 * (tspace0.mag_t + tspace1.mag_t); + ts_res.os = tspace0.os + tspace1.os; + ts_res.ot = tspace0.ot + tspace1.ot; + if v_not_zero(ts_res.os) { + ts_res.os = normalize(ts_res.os); + } + if v_not_zero(ts_res.ot) { + ts_res.ot = normalize(ts_res.ot); + } + } + ts_res +} + +fn normalize(v: Vec3) -> Vec3 { + (1.0 / v.length()) * v +} + +fn v_not_zero(v: Vec3) -> bool { + not_zero(v.x) || not_zero(v.y) || not_zero(v.z) +} + +#[allow(clippy::excessive_precision)] +fn not_zero(fx: f32) -> bool { + fx.abs() > 1.17549435e-38f32 +} + +fn eval_tspace( + geometry: &mut G, + face_indices_buffer: &[i32], + faces_count: i32, + vertex_indices: &[i32], + triangles_info: &[TriangleInfo], + vertex_representative: i32, +) -> TSpace { + let mut res: TSpace = TSpace { + os: Vec3::new(0.0, 0.0, 0.0), + mag_s: 0., + ot: Vec3::new(0.0, 0.0, 0.0), + mag_t: 0., + counter: 0, + orient: false, + }; + let mut angle_sum: f32 = 0i32 as f32; + res.os.x = 0.0f32; + res.os.y = 0.0f32; + res.os.z = 0.0f32; + res.ot.x = 0.0f32; + res.ot.y = 0.0f32; + res.ot.z = 0.0f32; + res.mag_s = 0i32 as f32; + res.mag_t = 0i32 as f32; + for face in 0..faces_count { + let f: i32 = face_indices_buffer[face as usize]; + + // only valid triangles get to add their contribution + if !triangles_info[f as usize] + .flags + .contains(TriangleFlags::GROUP_WITH_ANY) + { + let mut i: i32 = -1i32; + if vertex_indices[(3i32 * f) as usize] == vertex_representative { + i = 0i32; + } else if vertex_indices[(3i32 * f + 1i32) as usize] == vertex_representative { + i = 1i32; + } else if vertex_indices[(3i32 * f + 2i32) as usize] == vertex_representative { + i = 2i32; + } + let index = vertex_indices[(3i32 * f + i) as usize]; + let n = get_normal(geometry, index as usize); + let mut v_os = + triangles_info[f as usize].os - (n.dot(triangles_info[f as usize].os) * n); + let mut v_ot = + triangles_info[f as usize].ot - (n.dot(triangles_info[f as usize].ot) * n); + if v_not_zero(v_os) { + v_os = normalize(v_os); + } + if v_not_zero(v_ot) { + v_ot = normalize(v_ot); + } + let i2 = vertex_indices[(3i32 * f + if i < 2i32 { i + 1i32 } else { 0i32 }) as usize]; + let i1 = vertex_indices[(3i32 * f + i) as usize]; + let i0 = vertex_indices[(3i32 * f + if i > 0i32 { i - 1i32 } else { 2i32 }) as usize]; + let p0 = get_position(geometry, i0 as usize); + let p1 = get_position(geometry, i1 as usize); + let p2 = get_position(geometry, i2 as usize); + let v1 = p0 - p1; + let v2 = p2 - p1; + let mut v1 = v1 - (n.dot(v1) * n); + if v_not_zero(v1) { + v1 = normalize(v1); + } + let mut v2 = v2 - (n.dot(v2) * n); + if v_not_zero(v2) { + v2 = normalize(v2); + } + let cos = v1.dot(v2); + + let cos = if cos > 1.0 { + 1.0 + } else if cos < -1.0 { + -1.0 + } else { + cos + }; + let angle = (cos as f64).acos() as f32; + let mag_s = triangles_info[f as usize].mag_s; + let mag_t = triangles_info[f as usize].mag_t; + res.os += angle * v_os; + res.ot += angle * v_ot; + res.mag_s += angle * mag_s; + res.mag_t += angle * mag_t; + angle_sum += angle; + } + } + if v_not_zero(res.os) { + res.os = normalize(res.os); + } + if v_not_zero(res.ot) { + res.ot = normalize(res.ot); + } + if angle_sum > 0i32 as f32 { + res.mag_s /= angle_sum; + res.mag_t /= angle_sum; + } + res +} + +fn compare_sub_groups(pg1: &SubGroup, pg2: &SubGroup) -> bool { + let mut still_same: bool = true; + let mut i = 0; + if pg1.faces_count != pg2.faces_count { + return false; + } + while i < pg1.faces_count as usize && still_same { + still_same = pg1.tri_members[i] == pg2.tri_members[i]; + if still_same { + i += 1; + } + } + still_same +} + +fn quick_sort(sort_buffer: &mut [i32], left: i32, right: i32, mut seed: u32) { + // Random + let mut t: u32 = seed & 31i32 as u32; + t = seed.rotate_left(t) | seed.rotate_right((32i32 as u32).wrapping_sub(t)); + seed = seed.wrapping_add(t).wrapping_add(3i32 as u32); + // Random end + + let mut l = left; + let mut r = right; + let n = r - l + 1i32; + let index = seed.wrapping_rem(n as u32) as i32; + let mid = sort_buffer[(index + l) as usize]; + loop { + while sort_buffer[l as usize] < mid { + l += 1; + } + while sort_buffer[r as usize] > mid { + r -= 1; + } + if l <= r { + sort_buffer.swap(l as usize, r as usize); + l += 1; + r -= 1; + } + if l > r { + break; + } + } + if left < r { + quick_sort(sort_buffer, left, r, seed); + } + if l < right { + quick_sort(sort_buffer, l, right, seed); + } +} + +fn build_4_rule_groups( + triangles_info: &mut [TriangleInfo], + groups: &mut [Group], + face_indices_buffer: &mut [i32], + vertex_indices: &[i32], + triangles_count: i32, +) -> i32 { + let max_groups: i32 = triangles_count * 3i32; + let mut active_groups: i32 = 0i32; + let mut offset: i32 = 0i32; + for f in 0..triangles_count { + for i in 0..3i32 { + // if not assigned to a group + if !triangles_info[f as usize] + .flags + .contains(TriangleFlags::GROUP_WITH_ANY) + && triangles_info[f as usize].assigned_group[i as usize] == usize::MAX + { + let vert_index: i32 = vertex_indices[(f * 3i32 + i) as usize]; + assert!(active_groups < max_groups); + + let group_index = active_groups as usize; + triangles_info[f as usize].assigned_group[i as usize] = group_index; + let group = &mut groups[group_index]; + group.vertex_representative = vert_index; + group.orient_preservering = triangles_info[f as usize] + .flags + .contains(TriangleFlags::ORIENT_PRESERVING); + group.face_indices_len = 0; + group.face_indices_index = offset as usize; + active_groups += 1; + + add_tri_to_group(face_indices_buffer, group, f); + let or_pre = triangles_info[f as usize] + .flags + .contains(TriangleFlags::ORIENT_PRESERVING); + let neigh_index_l = triangles_info[f as usize].face_neighbors[i as usize]; + let neigh_index_r = triangles_info[f as usize].face_neighbors + [(if i > 0i32 { i - 1i32 } else { 2i32 }) as usize]; + if neigh_index_l >= 0i32 { + let answer: bool = assign_recur( + vertex_indices, + triangles_info, + neigh_index_l, + group, + group_index, + face_indices_buffer, + ); + let or_pre2: bool = triangles_info[neigh_index_l as usize] + .flags + .contains(TriangleFlags::ORIENT_PRESERVING); + let diff: bool = or_pre != or_pre2; + assert!(answer || diff); + } + if neigh_index_r >= 0i32 { + let answer: bool = assign_recur( + vertex_indices, + triangles_info, + neigh_index_r, + group, + group_index, + face_indices_buffer, + ); + let or_pre_2: bool = triangles_info[neigh_index_r as usize] + .flags + .contains(TriangleFlags::ORIENT_PRESERVING); + let diff: bool = or_pre != or_pre_2; + assert!(answer || diff); + } + + // update offset + offset += group.face_indices_len as i32; + + // since the groups are disjoint a triangle can never + // belong to more than 3 groups. Subsequently something + // is completely screwed if this assertion ever hits. + assert!(offset <= max_groups); + } + } + } + + active_groups +} + +fn assign_recur( + vertex_indices: &[i32], + triangles_info: &mut [TriangleInfo], + my_tri_index: i32, + group: &mut Group, + group_index: usize, + face_indices_buffer: &mut [i32], +) -> bool { + let my_tri_info = &mut triangles_info[my_tri_index as usize]; + + // track down vertex + let vert_rep: i32 = group.vertex_representative; + let offset = 3 * my_tri_index as usize; + let mut i: i32 = -1; + if vertex_indices[offset] == vert_rep { + i = 0; + } else if vertex_indices[offset + 1] == vert_rep { + i = 1; + } else if vertex_indices[offset + 2] == vert_rep { + i = 2; + } + assert!((0..3).contains(&i)); + + // early out + if my_tri_info.assigned_group[i as usize] == group_index { + return true; + } + if !my_tri_info.assigned_group[i as usize] == usize::MAX { + return false; + } + + if my_tri_info.flags.contains(TriangleFlags::GROUP_WITH_ANY) { + // first to group with a group-with-anything triangle + // determines it's orientation. + // This is the only existing order dependency in the code!! + if my_tri_info.assigned_group[0] == usize::MAX + && my_tri_info.assigned_group[1] == usize::MAX + && my_tri_info.assigned_group[2] == usize::MAX + { + my_tri_info + .flags + .set(TriangleFlags::ORIENT_PRESERVING, group.orient_preservering); + } + } + + let orient: bool = my_tri_info.flags.contains(TriangleFlags::ORIENT_PRESERVING); + if orient != group.orient_preservering { + return false; + } + + add_tri_to_group(face_indices_buffer, group, my_tri_index); + my_tri_info.assigned_group[i as usize] = group_index; + + let neigh_index_l = my_tri_info.face_neighbors[i as usize]; + let neigh_index_r = my_tri_info.face_neighbors[(if i > 0 { i - 1 } else { 2 }) as usize]; + if neigh_index_l >= 0 { + assign_recur( + vertex_indices, + triangles_info, + neigh_index_l, + group, + group_index, + face_indices_buffer, + ); + } + if neigh_index_r >= 0 { + assign_recur( + vertex_indices, + triangles_info, + neigh_index_r, + group, + group_index, + face_indices_buffer, + ); + } + + true +} + +fn add_tri_to_group(face_indices_buffer: &mut [i32], group: &mut Group, tri_index: i32) { + let offset = group.face_indices_index + group.face_indices_len; + face_indices_buffer[offset] = tri_index; + group.face_indices_len += 1; +} + +fn init_tri_info( + geometry: &mut G, + triangles_info: &mut [TriangleInfo], + vertex_indices: &[i32], + triangles_count: usize, +) { + let mut t = 0; + + // generate neighbor info list + #[allow(clippy::needless_range_loop)] + for f in 0..triangles_count { + for i in 0..3 { + triangles_info[f].face_neighbors[i as usize] = -1i32; + triangles_info[f].assigned_group[i as usize] = usize::MAX; + triangles_info[f].os.x = 0.0f32; + triangles_info[f].os.y = 0.0f32; + triangles_info[f].os.z = 0.0f32; + triangles_info[f].ot.x = 0.0f32; + triangles_info[f].ot.y = 0.0f32; + triangles_info[f].ot.z = 0.0f32; + triangles_info[f].mag_s = 0i32 as f32; + triangles_info[f].mag_t = 0i32 as f32; + + // assumed bad + triangles_info[f].flags |= TriangleFlags::GROUP_WITH_ANY; + } + } + + // evaluate first order derivatives + for f in 0..triangles_count { + let v1 = get_position(geometry, vertex_indices[f * 3] as usize); + let v2 = get_position(geometry, vertex_indices[f * 3 + 1] as usize); + let v3 = get_position(geometry, vertex_indices[f * 3 + 2] as usize); + let t1 = get_tex_coord(geometry, vertex_indices[f * 3] as usize); + let t2 = get_tex_coord(geometry, vertex_indices[f * 3 + 1] as usize); + let t3 = get_tex_coord(geometry, vertex_indices[f * 3 + 2] as usize); + let t21x: f32 = t2.x - t1.x; + let t21y: f32 = t2.y - t1.y; + let t31x: f32 = t3.x - t1.x; + let t31y: f32 = t3.y - t1.y; + let d1 = v2 - v1; + let d2 = v3 - v1; + let signed_arena_stx2: f32 = t21x * t31y - t21y * t31x; + let os = (t31y * d1) - (t21y * d2); + let ot = (-t31x * d1) + (t21x * d2); + + triangles_info[f] + .flags + .set(TriangleFlags::ORIENT_PRESERVING, signed_arena_stx2 > 0f32); + + if not_zero(signed_arena_stx2) { + let abs_arena: f32 = signed_arena_stx2.abs(); + let len_os: f32 = os.length(); + let len_ot: f32 = ot.length(); + let s: f32 = if !triangles_info[f] + .flags + .contains(TriangleFlags::ORIENT_PRESERVING) + { + -1.0f32 + } else { + 1.0f32 + }; + if not_zero(len_os) { + triangles_info[f].os = (s / len_os) * os; + } + if not_zero(len_ot) { + triangles_info[f].ot = (s / len_ot) * ot; + } + + // evaluate magnitudes prior to normalization of vOs and vOt + triangles_info[f].mag_s = len_os / abs_arena; + triangles_info[f].mag_t = len_ot / abs_arena; + + // if this is a good triangle + if not_zero(triangles_info[f].mag_s) && not_zero(triangles_info[f].mag_t) { + triangles_info[f] + .flags + .remove(TriangleFlags::GROUP_WITH_ANY); + } + } + } + + // force otherwise healthy quads to a fixed orientation + while t < triangles_count - 1 { + let fo_a: i32 = triangles_info[t].original_face_index; + let fo_b: i32 = triangles_info[t + 1].original_face_index; + if fo_a == fo_b { + let is_deg_a: bool = triangles_info[t] + .flags + .contains(TriangleFlags::MARK_DEGENERATE); + let is_deg_b: bool = triangles_info[t + 1] + .flags + .contains(TriangleFlags::MARK_DEGENERATE); + + // bad triangles should already have been removed by + // DegenPrologue(), but just in case check bIsDeg_a and bIsDeg_a are false + if !(is_deg_a || is_deg_b) { + let orient_a: bool = triangles_info[t] + .flags + .contains(TriangleFlags::ORIENT_PRESERVING); + let orient_b: bool = triangles_info[t + 1] + .flags + .contains(TriangleFlags::ORIENT_PRESERVING); + + // if this happens the quad has extremely bad mapping!! + if orient_a != orient_b { + let mut choose_orient_first_tri: bool = false; + if triangles_info[t + 1] + .flags + .contains(TriangleFlags::GROUP_WITH_ANY) + || calc_tex_area(geometry, vertex_indices, t * 3) + >= calc_tex_area(geometry, vertex_indices, (t + 1) * 3) + { + choose_orient_first_tri = true; + } + + // force match + let t0 = if choose_orient_first_tri { t } else { t + 1 }; + let t1_0 = if choose_orient_first_tri { t + 1 } else { t }; + + triangles_info[t1_0].flags.set( + TriangleFlags::ORIENT_PRESERVING, + triangles_info[t0] + .flags + .contains(TriangleFlags::ORIENT_PRESERVING), + ); + } + } + t += 2; + } else { + t += 1; + } + } + + let mut edges = vec![Edge::zero(); triangles_count * 3]; + build_neighbors_fast( + triangles_info, + &mut edges, + vertex_indices, + triangles_count as i32, + ); +} + +fn build_neighbors_fast( + triangles_info: &mut [TriangleInfo], + edges: &mut [Edge], + vertex_indices: &[i32], + triangles_count: i32, +) { + // build array of edges + // could replace with a random seed? + let seed: u32 = 39871946i32 as u32; + for f in 0..triangles_count { + for i in 0..3 { + let i0: i32 = vertex_indices[(f * 3i32 + i) as usize]; + let i1: i32 = + vertex_indices[(f * 3i32 + if i < 2i32 { i + 1i32 } else { 0i32 }) as usize]; + edges[(f * 3i32 + i) as usize].i0 = if i0 < i1 { i0 } else { i1 }; + edges[(f * 3i32 + i) as usize].i1 = if i0 >= i1 { i0 } else { i1 }; + edges[(f * 3i32 + i) as usize].f = f; + } + } + + // sort over all edges by i0, this is the pricy one. + quick_sort_edges(edges, 0i32, triangles_count * 3i32 - 1i32, 0i32, seed); + + // sub sort over i1, should be fast. + // could replace this with a 64 bit int sort over (i0,i1) + // with i0 as msb in the quicksort call above. + let entries = triangles_count * 3; + let mut cur_start_index = 0; + for i in 1..entries { + if edges[cur_start_index as usize].i0 != edges[i as usize].i0 { + let l: i32 = cur_start_index; + let r: i32 = i - 1i32; + cur_start_index = i; + quick_sort_edges(edges, l, r, 1i32, seed); + } + } + + // sub sort over f, which should be fast. + // this step is to remain compliant with BuildNeighborsSlow() when + // more than 2 triangles use the same edge (such as a butterfly topology). + cur_start_index = 0i32; + for i in 1..entries { + if edges[cur_start_index as usize].i0 != edges[i as usize].i0 + || edges[cur_start_index as usize].i1 != edges[i as usize].i1 + { + let l_0: i32 = cur_start_index; + let r_0: i32 = i - 1; + cur_start_index = i; + quick_sort_edges(edges, l_0, r_0, 2, seed); + } + } + + // pair up, adjacent triangles + for i in 0..entries { + let i0_0: i32 = edges[i as usize].i0; + let i1_0: i32 = edges[i as usize].i1; + let f_0: i32 = edges[i as usize].f; + let mut i0_a: i32 = 0; + let mut i1_a: i32 = 0; + let mut edgenum_a: i32 = 0; + let mut edgenum_b: i32 = 0; + get_edge( + &mut i0_a, + &mut i1_a, + &mut edgenum_a, + vertex_indices, + (f_0 * 3i32) as usize, + i0_0, + i1_0, + ); + let unassigned_a = triangles_info[f_0 as usize].face_neighbors[edgenum_a as usize] == -1; + if unassigned_a { + // get true index ordering + let mut j: i32 = i + 1i32; + let mut not_found: bool = true; + while j < entries + && i0_0 == edges[j as usize].i0 + && i1_0 == edges[j as usize].i1 + && not_found + { + let mut i0_b: i32 = 0; + let mut i1_b: i32 = 0; + let t = edges[j as usize].f; + get_edge( + &mut i1_b, + &mut i0_b, + &mut edgenum_b, + vertex_indices, + (t * 3i32) as usize, + edges[j as usize].i0, + edges[j as usize].i1, + ); + let unassigned_b = + triangles_info[t as usize].face_neighbors[edgenum_b as usize] == -1; + if i0_a == i0_b && i1_a == i1_b && unassigned_b { + not_found = false; + } else { + j += 1; + } + } + if !not_found { + let t_0: i32 = edges[j as usize].f; + triangles_info[f_0 as usize].face_neighbors[edgenum_a as usize] = t_0; + triangles_info[t_0 as usize].face_neighbors[edgenum_b as usize] = f_0; + } + } + } +} + +fn get_edge( + i0_out: &mut i32, + i1_out: &mut i32, + edgenum_out: &mut i32, + indices: &[i32], + offset: usize, + i0_in: i32, + i1_in: i32, +) { + let indices = &indices[offset..offset + 3]; + + *edgenum_out = -1i32; + if indices[0] == i0_in || indices[0] == i1_in { + if indices[1] == i0_in || indices[1] == i1_in { + *edgenum_out = 0i32; + *i0_out = indices[0]; + *i1_out = indices[1]; + } else { + *edgenum_out = 2i32; + *i0_out = indices[2]; + *i1_out = indices[0]; + } + } else { + *edgenum_out = 1i32; + *i0_out = indices[1]; + *i1_out = indices[2]; + }; } -fn face_vert_to_index(face: usize, vert: usize) -> usize { - face << 2 | vert & 0x3 +fn quick_sort_edges(sort_buffer: &mut [Edge], left: i32, right: i32, channel: i32, mut seed: u32) { + // early out + let elems: i32 = right - left + 1i32; + if elems < 2 { + return; + } + if elems == 2 { + if sort_buffer[left as usize].channel(channel) + > sort_buffer[right as usize].channel(channel) + { + sort_buffer.swap(left as usize, right as usize); + } + return; + } + + // Random + let mut t = seed & 31i32 as u32; + t = seed.rotate_left(t) | seed.rotate_right((32i32 as u32).wrapping_sub(t)); + seed = seed.wrapping_add(t).wrapping_add(3i32 as u32); + // Random end + + let mut l = left; + let mut r = right; + let n = r - l + 1i32; + let index = seed.wrapping_rem(n as u32) as i32; + let mid = sort_buffer[(index + l) as usize].channel(channel); + loop { + while sort_buffer[l as usize].channel(channel) < mid { + l += 1; + } + while sort_buffer[r as usize].channel(channel) > mid { + r -= 1; + } + if l <= r { + sort_buffer.swap(l as usize, r as usize); + l += 1; + r -= 1; + } + if l > r { + break; + } + } + if left < r { + quick_sort_edges(sort_buffer, left, r, channel, seed); + } + if l < right { + quick_sort_edges(sort_buffer, l, right, channel, seed); + }; +} + +// returns the texture area times 2 +fn calc_tex_area(geometry: &mut G, indices: &[i32], start: usize) -> f32 { + let t1 = get_tex_coord(geometry, indices[start] as usize); + let t2 = get_tex_coord(geometry, indices[start + 1] as usize); + let t3 = get_tex_coord(geometry, indices[start + 2] as usize); + let t21x: f32 = t2.x - t1.x; + let t21y: f32 = t2.y - t1.y; + let t31x: f32 = t3.x - t1.x; + let t31y: f32 = t3.y - t1.y; + let signed_area_stx2: f32 = t21x * t31y - t21y * t31x; + if signed_area_stx2 < 0i32 as f32 { + -signed_area_stx2 + } else { + signed_area_stx2 + } +} + +// degen triangles +fn degen_prologue( + triangles_info: &mut [TriangleInfo], + vertex_indices: &mut [i32], + triangles_count: i32, + total_triangles_count: i32, +) { + // locate quads with only one good triangle + let mut t: i32 = 0i32; + while t < total_triangles_count - 1i32 { + let fo_a: i32 = triangles_info[t as usize].original_face_index; + let fo_b: i32 = triangles_info[(t + 1i32) as usize].original_face_index; + if fo_a == fo_b { + let is_deg_a: bool = triangles_info[t as usize] + .flags + .contains(TriangleFlags::MARK_DEGENERATE); + let is_deg_b: bool = triangles_info[(t + 1) as usize] + .flags + .contains(TriangleFlags::MARK_DEGENERATE); + if is_deg_a ^ is_deg_b { + triangles_info[t as usize].flags |= TriangleFlags::QUAD_ONE_DEGEN_TRI; + triangles_info[(t + 1i32) as usize].flags |= TriangleFlags::QUAD_ONE_DEGEN_TRI; + } + t += 2i32; + } else { + t += 1; + } + } + + // reorder list so all degen triangles are moved to the back + // without reordering the good triangles + let mut next_good_triangle_search_index = 1i32; + t = 0i32; + let mut still_finding_good_ones = true; + while t < triangles_count && still_finding_good_ones { + let is_good: bool = !triangles_info[t as usize] + .flags + .contains(TriangleFlags::MARK_DEGENERATE); + if is_good { + if next_good_triangle_search_index < t + 2i32 { + next_good_triangle_search_index = t + 2i32; + } + } else { + // search for the first good triangle. + let mut just_a_degenerate: bool = true; + while just_a_degenerate && next_good_triangle_search_index < total_triangles_count { + let is_good_0: bool = !triangles_info[next_good_triangle_search_index as usize] + .flags + .contains(TriangleFlags::MARK_DEGENERATE); + if is_good_0 { + just_a_degenerate = false; + } else { + next_good_triangle_search_index += 1; + } + } + let t0 = t; + let t1 = next_good_triangle_search_index; + next_good_triangle_search_index += 1; + + // swap triangle t0 and t1 + if !just_a_degenerate { + for i in 0..3 { + vertex_indices.swap((t0 * 3 + i) as usize, (t1 * 3 + i) as usize); + } + triangles_info.swap(t0 as usize, t1 as usize); + } else { + still_finding_good_ones = false; + } + } + if still_finding_good_ones { + t += 1; + } + } +} + +fn generate_shared_vertices_index_list( + vertex_indices: &mut [i32], + geometry: &mut G, + triangles_count: usize, +) { + let mut min = get_position(geometry, 0); + let mut max = min; + + #[allow(clippy::needless_range_loop)] + for i in 1..triangles_count * 3 { + let index: i32 = vertex_indices[i]; + let p = get_position(geometry, index as usize); + if min.x > p.x { + min.x = p.x; + } else if max.x < p.x { + max.x = p.x; + } + if min.y > p.y { + min.y = p.y; + } else if max.y < p.y { + max.y = p.y; + } + if min.z > p.z { + min.z = p.z; + } else if max.z < p.z { + max.z = p.z; + } + } + let dim = max - min; + let mut channel = 0i32; + let mut f_min = min.x; + let mut f_max = max.x; + if dim.y > dim.x && dim.y > dim.z { + channel = 1i32; + f_min = min.y; + f_max = max.y; + } else if dim.z > dim.x { + channel = 2i32; + f_min = min.z; + f_max = max.z; + } + + let mut hash_table = vec![0i32; triangles_count * 3]; + let mut hash_offsets = vec![0i32; G_CELLS]; + let mut hash_count = vec![0i32; G_CELLS]; + let mut hash_count2 = vec![0i32; G_CELLS]; + + #[allow(clippy::needless_range_loop)] + for i in 0..triangles_count * 3 { + let index_0: i32 = vertex_indices[i]; + let p_0 = get_position(geometry, index_0 as usize); + let val: f32 = if channel == 0i32 { + p_0.x + } else if channel == 1i32 { + p_0.y + } else { + p_0.z + }; + let cell = find_grid_cell(f_min, f_max, val); + hash_count[cell] += 1; + } + hash_offsets[0] = 0i32; + let mut k = 1; + while k < G_CELLS { + hash_offsets[k] = hash_offsets[k - 1] + hash_count[k - 1]; + k += 1; + } + #[allow(clippy::needless_range_loop)] + for i in 0..triangles_count * 3 { + let index_1: i32 = vertex_indices[i]; + let p_1 = get_position(geometry, index_1 as usize); + let val_0: f32 = if channel == 0i32 { + p_1.x + } else if channel == 1i32 { + p_1.y + } else { + p_1.z + }; + let cell_0 = find_grid_cell(f_min, f_max, val_0); + hash_table[(hash_offsets[cell_0] + hash_count2[cell_0]) as usize] = i as i32; + hash_count2[cell_0] += 1; + } + k = 0; + while k < G_CELLS { + k += 1; + } + let mut max_count = hash_count[0] as usize; + k = 1; + while k < G_CELLS { + if max_count < hash_count[k] as usize { + max_count = hash_count[k] as usize; + } + k += 1; + } + let mut tmp_vert = vec![TmpVert::zero(); max_count]; + k = 0; + while k < G_CELLS { + // extract table of cell k and amount of entries in it + let table_0_offset = hash_offsets[k] as usize; + let entries = hash_count[k] as usize; + if entries >= 2 { + let mut e = 0; + while e < entries { + let i_0: i32 = hash_table[table_0_offset + e]; + let p_2 = get_position(geometry, vertex_indices[i_0 as usize] as usize); + tmp_vert[e].vert[0] = p_2.x; + tmp_vert[e].vert[1] = p_2.y; + tmp_vert[e].vert[2] = p_2.z; + tmp_vert[e].index = i_0; + e += 1; + } + merge_verts_fast( + geometry, + vertex_indices, + &mut tmp_vert, + 0i32, + (entries - 1) as i32, + ); + } + k += 1; + } +} + +fn merge_verts_fast( + geometry: &mut G, + vertex_indices: &mut [i32], + tmp_vert: &mut [TmpVert], + l_in: i32, + r_in: i32, +) { + // make bbox + let mut min: [f32; 3] = [0.; 3]; + let mut max: [f32; 3] = [0.; 3]; + for c in 0..3 { + min[c as usize] = tmp_vert[l_in as usize].vert[c as usize]; + max[c as usize] = min[c as usize]; + } + let mut l = l_in + 1i32; + while l <= r_in { + for c in 0..3 { + if min[c as usize] > tmp_vert[l as usize].vert[c as usize] { + min[c as usize] = tmp_vert[l as usize].vert[c as usize]; + } else if max[c as usize] < tmp_vert[l as usize].vert[c as usize] { + max[c as usize] = tmp_vert[l as usize].vert[c as usize]; + } + } + l += 1; + } + let dx = max[0usize] - min[0usize]; + let dy = max[1usize] - min[1usize]; + let dz = max[2usize] - min[2usize]; + let mut channel = 0i32; + if dy > dx && dy > dz { + channel = 1i32; + } else if dz > dx { + channel = 2i32; + } + let sep = 0.5f32 * (max[channel as usize] + min[channel as usize]); + if sep >= max[channel as usize] || sep <= min[channel as usize] { + l = l_in; + while l <= r_in { + let i: i32 = tmp_vert[l as usize].index; + let index: i32 = vertex_indices[i as usize]; + let p = get_position(geometry, index as usize); + let n = get_normal(geometry, index as usize); + let t = get_tex_coord(geometry, index as usize); + let mut not_found: bool = true; + let mut l2: i32 = l_in; + let mut i2rec: i32 = -1i32; + while l2 < l && not_found { + let i2: i32 = tmp_vert[l2 as usize].index; + let index2: i32 = vertex_indices[i2 as usize]; + let p2 = get_position(geometry, index2 as usize); + let n2 = get_normal(geometry, index2 as usize); + let t2 = get_tex_coord(geometry, index2 as usize); + i2rec = i2; + if p.x == p2.x + && p.y == p2.y + && p.z == p2.z + && n.x == n2.x + && n.y == n2.y + && n.z == n2.z + && t.x == t2.x + && t.y == t2.y + && t.z == t2.z + { + not_found = false; + } else { + l2 += 1; + } + } + if !not_found { + vertex_indices[i as usize] = vertex_indices[i2rec as usize]; + } + l += 1; + } + } else { + let mut l: i32 = l_in; + let mut r: i32 = r_in; + while l < r { + let mut ready_left_swap: bool = false; + let mut ready_right_swap: bool = false; + while !ready_left_swap && l < r { + ready_left_swap = tmp_vert[l as usize].vert[channel as usize] >= sep; + if !ready_left_swap { + l += 1; + } + } + while !ready_right_swap && l < r { + ready_right_swap = tmp_vert[r as usize].vert[channel as usize] < sep; + if !ready_right_swap { + r -= 1; + } + } + if ready_left_swap && ready_right_swap { + tmp_vert.swap(l as usize, r as usize); + l += 1; + r -= 1; + } + } + if l == r { + let ready_right_swap_0: bool = tmp_vert[r as usize].vert[channel as usize] < sep; + if ready_right_swap_0 { + l += 1; + } else { + r -= 1; + } + } + if l_in < r { + merge_verts_fast(geometry, vertex_indices, tmp_vert, l_in, r); + } + if l < r_in { + merge_verts_fast(geometry, vertex_indices, tmp_vert, l, r_in); + } + }; +} + +const G_CELLS: usize = 2048; + +// it is IMPORTANT that this function is called to evaluate the hash since +// inlining could potentially reorder instructions and generate different +// results for the same effective input value fVal. +#[inline(never)] +fn find_grid_cell(min: f32, max: f32, val: f32) -> usize { + let f_index = G_CELLS as f32 * ((val - min) / (max - min)); + let i_index = f_index as isize; + if i_index < G_CELLS as isize { + if i_index >= 0 { + i_index as usize + } else { + 0 + } + } else { + G_CELLS - 1 + } } diff --git a/crates/bevy_mikktspace/tests/regression_test.rs b/crates/bevy_mikktspace/tests/regression_test.rs index 42177cbc3496d..97675e15b5966 100644 --- a/crates/bevy_mikktspace/tests/regression_test.rs +++ b/crates/bevy_mikktspace/tests/regression_test.rs @@ -1,76 +1,30 @@ -#![allow( - clippy::bool_assert_comparison, - clippy::useless_conversion, - clippy::redundant_else, - clippy::match_same_arms, - clippy::semicolon_if_nothing_returned, - clippy::explicit_iter_loop, - clippy::map_flatten -)] +use std::{fs::File, io::Read}; use bevy_mikktspace::{generate_tangents, Geometry}; -use glam::{Vec2, Vec3}; - -pub type Face = [u32; 3]; - -#[derive(Debug)] -struct Vertex { - position: Vec3, - normal: Vec3, - tex_coord: Vec2, -} - -#[derive(Debug, PartialEq)] -struct Result { - tangent: [f32; 3], - bi_tangent: [f32; 3], - mag_s: f32, - mag_t: f32, - bi_tangent_preserves_orientation: bool, - face: usize, - vert: usize, -} - -impl Result { - fn new( - tangent: [f32; 3], - bi_tangent: [f32; 3], - mag_s: f32, - mag_t: f32, - bi_tangent_preserves_orientation: bool, - face: usize, - vert: usize, - ) -> Self { - Self { - tangent, - bi_tangent, - mag_s, - mag_t, - bi_tangent_preserves_orientation, - face, - vert, - } - } -} +use bytemuck::{bytes_of_mut, cast_slice_mut, Pod, Zeroable}; struct Mesh { - faces: Vec, vertices: Vec, + indices: Vec, } -struct Context { - mesh: Mesh, - results: Vec, +#[derive(Pod, Zeroable, Default, Debug, Clone, Copy)] +#[repr(C)] +struct Vertex { + position: [f32; 3], + normal: [f32; 3], + texture_coords: [f32; 2], + tangent: [f32; 3], } fn vertex(mesh: &Mesh, face: usize, vert: usize) -> &Vertex { - let vs: &[u32; 3] = &mesh.faces[face]; - &mesh.vertices[vs[vert] as usize] + let index = mesh.indices[(face * 3) + vert]; + &mesh.vertices[index as usize] } -impl Geometry for Context { +impl Geometry for Mesh { fn num_faces(&self) -> usize { - self.mesh.faces.len() + self.indices.len() / 3 } fn num_vertices_of_face(&self, _face: usize) -> usize { @@ -78,812 +32,101 @@ impl Geometry for Context { } fn position(&self, face: usize, vert: usize) -> [f32; 3] { - vertex(&self.mesh, face, vert).position.into() + vertex(self, face, vert).position } fn normal(&self, face: usize, vert: usize) -> [f32; 3] { - vertex(&self.mesh, face, vert).normal.into() + vertex(self, face, vert).normal } fn tex_coord(&self, face: usize, vert: usize) -> [f32; 2] { - vertex(&self.mesh, face, vert).tex_coord.into() + vertex(self, face, vert).texture_coords } fn set_tangent( &mut self, tangent: [f32; 3], - bi_tangent: [f32; 3], - mag_s: f32, - mag_t: f32, - bi_tangent_preserves_orientation: bool, + _bi_tangent: [f32; 3], + _mag_s: f32, + _mag_t: f32, + _bi_tangent_preserves_orientation: bool, face: usize, vert: usize, ) { - self.results.push(Result { - tangent, - bi_tangent, - mag_s, - mag_t, - bi_tangent_preserves_orientation, - face, - vert, - }) + let index = self.indices[(face * 3) + vert]; + self.vertices[index as usize].tangent = tangent; } } -struct ControlPoint { - uv: [f32; 2], - dir: [f32; 3], -} +fn load_mesh(path: &str) -> Mesh { + println!("loading mesh data"); + let mut mesh = Mesh { + vertices: Vec::new(), + indices: Vec::new(), + }; -impl ControlPoint { - fn new(uv: [f32; 2], dir: [f32; 3]) -> Self { - Self { uv, dir } - } -} + // Open the file + let mut file = File::open(path).unwrap(); -fn make_cube() -> Mesh { - let mut faces = Vec::new(); - let mut ctl_pts = Vec::new(); - let mut vertices = Vec::new(); + // Read the vertices + let mut vertices_len = 0u32; + file.read_exact(bytes_of_mut(&mut vertices_len)).unwrap(); - // +x plane - { - let base = ctl_pts.len() as u32; - faces.push([base, base + 1, base + 4]); - faces.push([base + 1, base + 2, base + 4]); - faces.push([base + 2, base + 3, base + 4]); - faces.push([base + 3, base, base + 4]); - ctl_pts.push(ControlPoint::new([0.0, 0.0], [1.0, -1.0, 1.0])); - ctl_pts.push(ControlPoint::new([0.0, 1.0], [1.0, -1.0, -1.0])); - ctl_pts.push(ControlPoint::new([1.0, 1.0], [1.0, 1.0, -1.0])); - ctl_pts.push(ControlPoint::new([1.0, 0.0], [1.0, 1.0, 1.0])); - ctl_pts.push(ControlPoint::new([0.5, 0.5], [1.0, 0.0, 0.0])); - } + mesh.vertices = vec![Vertex::default(); vertices_len as usize]; + file.read_exact(cast_slice_mut(&mut mesh.vertices)).unwrap(); - // -x plane - { - let base = ctl_pts.len() as u32; - faces.push([base, base + 1, base + 4]); - faces.push([base + 1, base + 2, base + 4]); - faces.push([base + 2, base + 3, base + 4]); - faces.push([base + 3, base, base + 4]); - ctl_pts.push(ControlPoint::new([1.0, 0.0], [-1.0, 1.0, 1.0])); - ctl_pts.push(ControlPoint::new([1.0, 1.0], [-1.0, 1.0, -1.0])); - ctl_pts.push(ControlPoint::new([0.0, 1.0], [-1.0, -1.0, -1.0])); - ctl_pts.push(ControlPoint::new([0.0, 0.0], [-1.0, -1.0, 1.0])); - ctl_pts.push(ControlPoint::new([0.5, 0.5], [-1.0, 0.0, 0.0])); - } + // Read the indices + let mut indices_len = 0u32; + file.read_exact(bytes_of_mut(&mut indices_len)).unwrap(); - // +y plane - { - let base = ctl_pts.len() as u32; - faces.push([base, base + 1, base + 4]); - faces.push([base + 1, base + 2, base + 4]); - faces.push([base + 2, base + 3, base + 4]); - faces.push([base + 3, base, base + 4]); - ctl_pts.push(ControlPoint::new([0.0, 0.0], [1.0, 1.0, 1.0])); - ctl_pts.push(ControlPoint::new([0.0, 1.0], [1.0, 1.0, -1.0])); - ctl_pts.push(ControlPoint::new([0.0, 1.0], [-1.0, 1.0, -1.0])); - ctl_pts.push(ControlPoint::new([0.0, 0.0], [-1.0, 1.0, 1.0])); - ctl_pts.push(ControlPoint::new([0.0, 0.5], [0.0, 1.0, 0.0])); - } + mesh.indices = vec![0; indices_len as usize]; + file.read_exact(cast_slice_mut(&mut mesh.indices)).unwrap(); - // -y plane - { - let base = ctl_pts.len() as u32; - faces.push([base, base + 1, base + 4]); - faces.push([base + 1, base + 2, base + 4]); - faces.push([base + 2, base + 3, base + 4]); - faces.push([base + 3, base, base + 4]); - ctl_pts.push(ControlPoint::new([0.0, 0.0], [-1.0, -1.0, 1.0])); - ctl_pts.push(ControlPoint::new([0.0, 1.0], [-1.0, -1.0, -1.0])); - ctl_pts.push(ControlPoint::new([0.0, 1.0], [1.0, -1.0, -1.0])); - ctl_pts.push(ControlPoint::new([0.0, 0.0], [1.0, -1.0, 1.0])); - ctl_pts.push(ControlPoint::new([0.0, 0.5], [0.0, -1.0, 0.0])); - } + println!("read {} vertices, {} indices", vertices_len, indices_len); - // +z plane - { - let base = ctl_pts.len() as u32; - faces.push([base, base + 1, base + 4]); - faces.push([base + 1, base + 2, base + 4]); - faces.push([base + 2, base + 3, base + 4]); - faces.push([base + 3, base, base + 4]); - ctl_pts.push(ControlPoint::new([0.0, 0.0], [-1.0, 1.0, 1.0])); - ctl_pts.push(ControlPoint::new([0.0, 1.0], [-1.0, -1.0, 1.0])); - ctl_pts.push(ControlPoint::new([1.0, 1.0], [1.0, -1.0, 1.0])); - ctl_pts.push(ControlPoint::new([1.0, 0.0], [1.0, 1.0, 1.0])); - ctl_pts.push(ControlPoint::new([0.5, 0.5], [0.0, 0.0, 1.0])); - } + mesh +} + +fn match_at(path: &str) { + // Load the mesh + let mut mesh = load_mesh(path); - // -z plane - { - let base = ctl_pts.len() as u32; - faces.push([base, base + 1, base + 4]); - faces.push([base + 1, base + 2, base + 4]); - faces.push([base + 2, base + 3, base + 4]); - faces.push([base + 3, base, base + 4]); - ctl_pts.push(ControlPoint::new([1.0, 0.0], [1.0, 1.0, -1.0])); - ctl_pts.push(ControlPoint::new([1.0, 1.0], [1.0, -1.0, -1.0])); - ctl_pts.push(ControlPoint::new([0.0, 1.0], [-1.0, -1.0, -1.0])); - ctl_pts.push(ControlPoint::new([0.0, 0.0], [-1.0, 1.0, -1.0])); - ctl_pts.push(ControlPoint::new([0.5, 0.5], [0.0, 0.0, -1.0])); + // Store the original reference values, and zero tangents just in case + let original = mesh.vertices.clone(); + for vertex in &mut mesh.vertices { + vertex.tangent = [0.0, 0.0, 0.0]; } - for pt in ctl_pts { - let p: Vec3 = pt.dir.into(); - let n: Vec3 = p.normalize(); - let t: Vec2 = pt.uv.into(); - vertices.push(Vertex { - position: (p / 2.0).into(), - normal: n.into(), - tex_coord: t.into(), - }); + // Perform tangent generation + println!("generating tangents"); + generate_tangents(&mut mesh); + + // Match against original + assert!(!original.is_empty()); + assert_eq!(original.len(), mesh.vertices.len()); + println!("validating {} tangents", original.len()); + for (i, original) in original.iter().enumerate() { + assert_eq!(original.tangent, mesh.vertices[i].tangent); } +} - Mesh { faces, vertices } +#[test] +fn match_cube() { + match_at("data/cube.bin"); } #[test] -fn cube_tangents_should_equal_reference_values() { - let mut context = Context { - mesh: make_cube(), - results: Vec::new(), - }; - let ret = generate_tangents(&mut context); - assert_eq!(true, ret); +fn match_suzanne_flat() { + match_at("data/suzanne_flat_tris.bin"); +} - let expected_results: Vec = vec![ - Result::new( - [0.40824825, 0.81649655, 0.40824825], - [0.40824825, -0.40824825, -0.81649655], - 1.00000000, - 1.00000000, - false, - 0, - 0, - ), - Result::new( - [0.40824825, 0.81649655, -0.40824825], - [-0.40824825, 0.40824825, -0.81649655], - 1.00000000, - 1.00000000, - false, - 0, - 1, - ), - Result::new( - [0.00000000, 1.00000000, 0.00000000], - [0.00000000, 0.00000000, -1.00000000], - 1.00000000, - 1.00000000, - false, - 0, - 2, - ), - Result::new( - [0.40824825, 0.81649655, -0.40824825], - [-0.40824825, 0.40824825, -0.81649655], - 1.00000000, - 1.00000000, - false, - 1, - 0, - ), - Result::new( - [-0.40824825, 0.81649655, 0.40824825], - [-0.40824825, -0.40824825, -0.81649655], - 1.00000000, - 1.00000000, - false, - 1, - 1, - ), - Result::new( - [0.00000000, 1.00000000, 0.00000000], - [0.00000000, 0.00000000, -1.00000000], - 1.00000000, - 1.00000000, - false, - 1, - 2, - ), - Result::new( - [-0.40824825, 0.81649655, 0.40824825], - [-0.40824825, -0.40824825, -0.81649655], - 1.00000000, - 1.00000000, - false, - 2, - 0, - ), - Result::new( - [-0.40824825, 0.81649655, -0.40824825], - [0.40824825, 0.40824825, -0.81649655], - 1.00000000, - 1.00000000, - false, - 2, - 1, - ), - Result::new( - [0.00000000, 1.00000000, 0.00000000], - [0.00000000, 0.00000000, -1.00000000], - 1.00000000, - 1.00000000, - false, - 2, - 2, - ), - Result::new( - [-0.40824825, 0.81649655, -0.40824825], - [0.40824825, 0.40824825, -0.81649655], - 1.00000000, - 1.00000000, - false, - 3, - 0, - ), - Result::new( - [0.40824825, 0.81649655, 0.40824825], - [0.40824825, -0.40824825, -0.81649655], - 1.00000000, - 1.00000000, - false, - 3, - 1, - ), - Result::new( - [0.00000000, 1.00000000, 0.00000000], - [0.00000000, 0.00000000, -1.00000000], - 1.00000000, - 1.00000000, - false, - 3, - 2, - ), - Result::new( - [0.40824825, 0.81649655, -0.40824825], - [-0.40824825, 0.40824825, -0.81649655], - 1.00000000, - 1.00000000, - true, - 4, - 0, - ), - Result::new( - [0.40824825, 0.81649655, 0.40824825], - [0.40824825, -0.40824825, -0.81649655], - 1.00000000, - 1.00000000, - true, - 4, - 1, - ), - Result::new( - [0.00000000, 1.00000000, 0.00000000], - [0.00000000, 0.00000000, -1.00000000], - 1.00000000, - 1.00000000, - true, - 4, - 2, - ), - Result::new( - [0.40824825, 0.81649655, 0.40824825], - [0.40824825, -0.40824825, -0.81649655], - 1.00000000, - 1.00000000, - true, - 5, - 0, - ), - Result::new( - [-0.40824825, 0.81649655, -0.40824825], - [0.40824825, 0.40824825, -0.81649655], - 1.00000000, - 1.00000000, - true, - 5, - 1, - ), - Result::new( - [0.00000000, 1.00000000, 0.00000000], - [0.00000000, 0.00000000, -1.00000000], - 1.00000000, - 1.00000000, - true, - 5, - 2, - ), - Result::new( - [-0.40824825, 0.81649655, -0.40824825], - [0.40824825, 0.40824825, -0.81649655], - 1.00000000, - 1.00000000, - true, - 6, - 0, - ), - Result::new( - [-0.40824825, 0.81649655, 0.40824825], - [-0.40824825, -0.40824825, -0.81649655], - 1.00000000, - 1.00000000, - true, - 6, - 1, - ), - Result::new( - [0.00000000, 1.00000000, 0.00000000], - [0.00000000, 0.00000000, -1.00000000], - 1.00000000, - 1.00000000, - true, - 6, - 2, - ), - Result::new( - [-0.40824825, 0.81649655, 0.40824825], - [-0.40824825, -0.40824825, -0.81649655], - 1.00000000, - 1.00000000, - true, - 7, - 0, - ), - Result::new( - [0.40824825, 0.81649655, -0.40824825], - [-0.40824825, 0.40824825, -0.81649655], - 1.00000000, - 1.00000000, - true, - 7, - 1, - ), - Result::new( - [0.00000000, 1.00000000, 0.00000000], - [0.00000000, 0.00000000, -1.00000000], - 1.00000000, - 1.00000000, - true, - 7, - 2, - ), - Result::new( - [1.00000000, 0.00000000, 0.00000000], - [0.00000000, 1.00000000, 0.00000000], - 1.00000000, - 1.00000000, - false, - 8, - 0, - ), - Result::new( - [1.00000000, 0.00000000, 0.00000000], - [0.00000000, 1.00000000, 0.00000000], - 1.00000000, - 1.00000000, - false, - 8, - 1, - ), - Result::new( - [1.00000000, 0.00000000, 0.00000000], - [0.00000000, 1.00000000, 0.00000000], - 1.00000000, - 1.00000000, - false, - 8, - 2, - ), - Result::new( - [1.00000000, 0.00000000, 0.00000000], - [0.00000000, 1.00000000, 0.00000000], - 1.00000000, - 1.00000000, - false, - 9, - 0, - ), - Result::new( - [1.00000000, 0.00000000, 0.00000000], - [0.00000000, 1.00000000, 0.00000000], - 1.00000000, - 1.00000000, - false, - 9, - 1, - ), - Result::new( - [1.00000000, 0.00000000, 0.00000000], - [0.00000000, 1.00000000, 0.00000000], - 1.00000000, - 1.00000000, - false, - 9, - 2, - ), - Result::new( - [1.00000000, 0.00000000, 0.00000000], - [0.00000000, 1.00000000, 0.00000000], - 1.00000000, - 1.00000000, - false, - 10, - 0, - ), - Result::new( - [1.00000000, 0.00000000, 0.00000000], - [0.00000000, 1.00000000, 0.00000000], - 1.00000000, - 1.00000000, - false, - 10, - 1, - ), - Result::new( - [1.00000000, 0.00000000, 0.00000000], - [0.00000000, 1.00000000, 0.00000000], - 1.00000000, - 1.00000000, - false, - 10, - 2, - ), - Result::new( - [1.00000000, 0.00000000, 0.00000000], - [0.00000000, 1.00000000, 0.00000000], - 1.00000000, - 1.00000000, - false, - 11, - 0, - ), - Result::new( - [1.00000000, 0.00000000, 0.00000000], - [0.00000000, 1.00000000, 0.00000000], - 1.00000000, - 1.00000000, - false, - 11, - 1, - ), - Result::new( - [1.00000000, 0.00000000, 0.00000000], - [0.00000000, 1.00000000, 0.00000000], - 1.00000000, - 1.00000000, - false, - 11, - 2, - ), - Result::new( - [-0.40824825, 0.81649655, 0.40824825], - [-0.40824825, -0.40824825, -0.81649655], - 1.00000000, - 1.00000000, - true, - 12, - 0, - ), - Result::new( - [-0.40824825, 0.81649655, -0.40824825], - [0.40824825, 0.40824825, -0.81649655], - 1.00000000, - 1.00000000, - true, - 12, - 1, - ), - Result::new( - [1.00000000, 0.00000000, 0.00000000], - [0.00000000, 1.00000000, 0.00000000], - 1.00000000, - 1.00000000, - false, - 12, - 2, - ), - Result::new( - [1.00000000, 0.00000000, 0.00000000], - [0.00000000, 1.00000000, 0.00000000], - 1.00000000, - 1.00000000, - false, - 13, - 0, - ), - Result::new( - [0.40824825, 0.81649655, -0.40824825], - [-0.40824825, 0.40824825, -0.81649655], - 1.00000000, - 1.00000000, - false, - 13, - 1, - ), - Result::new( - [1.00000000, 0.00000000, 0.00000000], - [0.00000000, 1.00000000, 0.00000000], - 1.00000000, - 1.00000000, - false, - 13, - 2, - ), - Result::new( - [0.40824825, 0.81649655, -0.40824825], - [-0.40824825, 0.40824825, -0.81649655], - 1.00000000, - 1.00000000, - false, - 14, - 0, - ), - Result::new( - [0.40824825, 0.81649655, 0.40824825], - [0.40824825, -0.40824825, -0.81649655], - 1.00000000, - 1.00000000, - false, - 14, - 1, - ), - Result::new( - [1.00000000, 0.00000000, 0.00000000], - [0.00000000, 1.00000000, 0.00000000], - 1.00000000, - 1.00000000, - false, - 14, - 2, - ), - Result::new( - [0.40824825, 0.81649655, 0.40824825], - [0.40824825, -0.40824825, -0.81649655], - 1.00000000, - 1.00000000, - false, - 15, - 0, - ), - Result::new( - [1.00000000, 0.00000000, 0.00000000], - [0.00000000, 1.00000000, 0.00000000], - 1.00000000, - 1.00000000, - false, - 15, - 1, - ), - Result::new( - [1.00000000, 0.00000000, 0.00000000], - [0.00000000, 1.00000000, 0.00000000], - 1.00000000, - 1.00000000, - false, - 15, - 2, - ), - Result::new( - [0.81649655, 0.40824825, 0.40824825], - [-0.40824825, -0.81649655, 0.40824825], - 1.00000000, - 1.00000000, - false, - 16, - 0, - ), - Result::new( - [0.81649655, -0.40824825, 0.40824825], - [0.40824825, -0.81649655, -0.40824825], - 1.00000000, - 1.00000000, - false, - 16, - 1, - ), - Result::new( - [1.00000000, 0.00000000, 0.00000000], - [0.00000000, -1.00000000, 0.00000000], - 1.00000000, - 1.00000000, - false, - 16, - 2, - ), - Result::new( - [0.81649655, -0.40824825, 0.40824825], - [0.40824825, -0.81649655, -0.40824825], - 1.00000000, - 1.00000000, - false, - 17, - 0, - ), - Result::new( - [0.81649655, 0.40824825, -0.40824825], - [-0.40824825, -0.81649655, -0.40824825], - 1.00000000, - 1.00000000, - false, - 17, - 1, - ), - Result::new( - [1.00000000, 0.00000000, 0.00000000], - [0.00000000, -1.00000000, 0.00000000], - 1.00000000, - 1.00000000, - false, - 17, - 2, - ), - Result::new( - [0.81649655, 0.40824825, -0.40824825], - [-0.40824825, -0.81649655, -0.40824825], - 1.00000000, - 1.00000000, - false, - 18, - 0, - ), - Result::new( - [0.81649655, -0.40824825, -0.40824825], - [0.40824825, -0.81649655, 0.40824825], - 1.00000000, - 1.00000000, - false, - 18, - 1, - ), - Result::new( - [1.00000000, 0.00000000, 0.00000000], - [0.00000000, -1.00000000, 0.00000000], - 1.00000000, - 1.00000000, - false, - 18, - 2, - ), - Result::new( - [0.81649655, -0.40824825, -0.40824825], - [0.40824825, -0.81649655, 0.40824825], - 1.00000000, - 1.00000000, - false, - 19, - 0, - ), - Result::new( - [0.81649655, 0.40824825, 0.40824825], - [-0.40824825, -0.81649655, 0.40824825], - 1.00000000, - 1.00000000, - false, - 19, - 1, - ), - Result::new( - [1.00000000, 0.00000000, 0.00000000], - [0.00000000, -1.00000000, 0.00000000], - 1.00000000, - 1.00000000, - false, - 19, - 2, - ), - Result::new( - [0.81649655, -0.40824825, 0.40824825], - [0.40824825, -0.81649655, -0.40824825], - 1.00000000, - 1.00000000, - true, - 20, - 0, - ), - Result::new( - [0.81649655, 0.40824825, 0.40824825], - [-0.40824825, -0.81649655, 0.40824825], - 1.00000000, - 1.00000000, - true, - 20, - 1, - ), - Result::new( - [1.00000000, 0.00000000, 0.00000000], - [0.00000000, -1.00000000, 0.00000000], - 1.00000000, - 1.00000000, - true, - 20, - 2, - ), - Result::new( - [0.81649655, 0.40824825, 0.40824825], - [-0.40824825, -0.81649655, 0.40824825], - 1.00000000, - 1.00000000, - true, - 21, - 0, - ), - Result::new( - [0.81649655, -0.40824825, -0.40824825], - [0.40824825, -0.81649655, 0.40824825], - 1.00000000, - 1.00000000, - true, - 21, - 1, - ), - Result::new( - [1.00000000, 0.00000000, 0.00000000], - [0.00000000, -1.00000000, 0.00000000], - 1.00000000, - 1.00000000, - true, - 21, - 2, - ), - Result::new( - [0.81649655, -0.40824825, -0.40824825], - [0.40824825, -0.81649655, 0.40824825], - 1.00000000, - 1.00000000, - true, - 22, - 0, - ), - Result::new( - [0.81649655, 0.40824825, -0.40824825], - [-0.40824825, -0.81649655, -0.40824825], - 1.00000000, - 1.00000000, - true, - 22, - 1, - ), - Result::new( - [1.00000000, 0.00000000, 0.00000000], - [0.00000000, -1.00000000, 0.00000000], - 1.00000000, - 1.00000000, - true, - 22, - 2, - ), - Result::new( - [0.81649655, 0.40824825, -0.40824825], - [-0.40824825, -0.81649655, -0.40824825], - 1.00000000, - 1.00000000, - true, - 23, - 0, - ), - Result::new( - [0.81649655, -0.40824825, 0.40824825], - [0.40824825, -0.81649655, -0.40824825], - 1.00000000, - 1.00000000, - true, - 23, - 1, - ), - Result::new( - [1.00000000, 0.00000000, 0.00000000], - [0.00000000, -1.00000000, 0.00000000], - 1.00000000, - 1.00000000, - true, - 23, - 2, - ), - ]; +#[test] +fn match_suzanne_smooth() { + match_at("data/suzanne_smooth_tris.bin"); +} - assert_eq!(expected_results, context.results); +#[test] +fn match_suzanne_bad() { + // This model intentionally contains bad faces that can't have tangents generated for it + match_at("data/suzanne_bad.bin"); }