#[cfg(feature = "monstertruck")]
use monstertruck::step::save::*;
use opensubdiv_petite::far::{
AdaptiveRefinementOptions, EndCapType, PatchTable, PatchTableOptions, PrimvarRefiner,
TopologyDescriptor, TopologyRefiner, TopologyRefinerOptions,
};
#[cfg(feature = "monstertruck")]
use opensubdiv_petite::monstertruck::PatchTableExt;
#[cfg(feature = "monstertruck")]
fn main() -> Result<(), Box<dyn std::error::Error>> {
let vertex_positions = vec![
[-0.5, -0.5, -0.5], [0.5, -0.5, -0.5], [-0.5, 0.5, -0.5], [0.5, 0.5, -0.5], [-0.5, 0.5, 0.5], [0.5, 0.5, 0.5], [-0.5, -0.5, 0.5], [0.5, -0.5, 0.5], ];
let face_vertex_counts = vec![4, 4, 4, 4, 4, 4];
let face_vertex_indices = vec![
0, 1, 3, 2, 2, 3, 5, 4, 4, 5, 7, 6, 6, 7, 1, 0, 0, 2, 4, 6, 1, 7, 5, 3, ];
let descriptor = TopologyDescriptor::new(
vertex_positions.len(),
&face_vertex_counts,
&face_vertex_indices,
)?;
let refiner_options = TopologyRefinerOptions::default();
let mut refiner = TopologyRefiner::new(descriptor, refiner_options)?;
let mut adaptive_options = AdaptiveRefinementOptions::default();
adaptive_options.isolation_level = 3;
refiner.refine_adaptive(adaptive_options, &[]);
let patch_options = PatchTableOptions::new()
.end_cap_type(EndCapType::GregoryBasis)
.use_inf_sharp_patch(false);
let patch_table = PatchTable::new(&refiner, Some(patch_options))?;
let primvar_refiner = PrimvarRefiner::new(&refiner)?;
let mut all_vertices = Vec::with_capacity(refiner.vertex_count_all_levels());
all_vertices.extend_from_slice(&vertex_positions);
for level in 1..refiner.refinement_levels() {
let src_data: Vec<f32> = all_vertices
[(all_vertices.len() - refiner.level(level - 1).unwrap().vertex_count())..]
.iter()
.flat_map(|v| v.iter().copied())
.collect();
if let Some(refined) = primvar_refiner.interpolate(level, 3, &src_data) {
let level_vertices: Vec<[f32; 3]> = refined
.chunks_exact(3)
.map(|chunk| [chunk[0], chunk[1], chunk[2]])
.collect();
all_vertices.extend_from_slice(&level_vertices);
}
}
let num_local_points = patch_table.local_point_count();
if num_local_points > 0 {
if let Some(stencil_table) = patch_table.local_point_stencil_table() {
let mut local_points = Vec::with_capacity(num_local_points);
for dim in 0..3 {
let src_dim: Vec<f32> = all_vertices.iter().map(|v| v[dim]).collect();
let dst_dim = stencil_table.update_values(&src_dim, None, None);
for (i, &val) in dst_dim.iter().enumerate() {
if dim == 0 {
local_points.push([val, 0.0, 0.0]);
} else {
local_points[i][dim] = val;
}
}
}
all_vertices.extend_from_slice(&local_points);
}
}
println!("Testing regular conversion...");
match patch_table.to_monstertruck_shell(&all_vertices) {
Ok(shell) => {
let compressed = shell.compress();
let step_string =
CompleteStepDisplay::new(StepModel::from(&compressed), Default::default())
.to_string();
std::fs::write("cube_regular.step", step_string)?;
println!("Wrote cube_regular.step");
}
Err(e) => println!("Regular conversion failed: {:?}", e),
}
println!("Testing gap-filling conversion...");
match patch_table.to_monstertruck_shell_with_gap_filling(&all_vertices) {
Ok(shell) => {
let compressed = shell.compress();
let step_string =
CompleteStepDisplay::new(StepModel::from(&compressed), Default::default())
.to_string();
std::fs::write("cube_gap_filled.step", step_string)?;
println!("Wrote cube_gap_filled.step");
}
Err(e) => println!("Gap-filling conversion failed: {:?}", e),
}
Ok(())
}
#[cfg(not(feature = "monstertruck"))]
fn main() {
println!("This example requires the 'monstertruck' feature. Run with:");
println!(" cargo run --example test_cube_export --features monstertruck");
}