forked from 1b-agent/opencadstudio-upstream
* helpers::wcs_to_ucs — UCS inverse transform with zero call sites. * scene::Scene::compute_and_set_world_offset — never called; the load path uses the free function `compute_world_offset` directly. * tessellate::tessellate_mesh — never called; mesh tessellation goes through `solid3d_tess`, not the truck Shell/Solid path. * truck_tess::tess_to_mesh_model — orphaned with tessellate_mesh's removal. * MeshModel::WHITE / MeshModel::SELECTED — only used by the removed tessellate_mesh. * xattach::Step::FilePath variant — never constructed; XATTACH always enters through `with_path` after the file picker. Replaced the Step enum + prefilled_path field with flat `path` / `block_name` fields and dropped the unreachable text-input flow. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
70 lines
2.5 KiB
Rust
70 lines
2.5 KiB
Rust
// Triangle mesh model — produced by truck Shell/Solid tessellation.
|
||
//
|
||
// Stored alongside WireModels in the scene; rendered by the mesh pipeline
|
||
// (wgpu TriangleList with depth test, flat normals).
|
||
|
||
/// A tessellated triangle mesh ready to upload to the GPU.
|
||
#[derive(Clone, Debug)]
|
||
#[allow(dead_code)]
|
||
pub struct MeshModel {
|
||
/// Unique identifier (entity handle value as decimal string).
|
||
pub name: String,
|
||
/// World-space vertex positions.
|
||
pub verts: Vec<[f32; 3]>,
|
||
/// Per-vertex normals (may be empty if not available).
|
||
pub normals: Vec<[f32; 3]>,
|
||
/// Triangle indices into `verts` (every 3 values = one triangle).
|
||
pub indices: Vec<u32>,
|
||
/// RGBA colour in [0, 1].
|
||
pub color: [f32; 4],
|
||
/// Whether this mesh is currently selected.
|
||
pub selected: bool,
|
||
}
|
||
|
||
/// Bundle of mesh tessellations at different sampling densities, picked
|
||
/// per frame by the render pipeline based on the projected pixel size of
|
||
/// `world_aabb`. Phase 3.4 LOD ladder:
|
||
///
|
||
/// | LOD | Source | Use when projected diagonal |
|
||
/// |-----|------------|------------------------------|
|
||
/// | 0 | HIGH | > 200 px |
|
||
/// | 1 | MID (½) | 50–200 px |
|
||
/// | 2 | LOW (¼) | < 50 px |
|
||
///
|
||
/// `lods` holds up to one MeshModel per LOD level (high → low). Empty
|
||
/// slots fall back to the nearest available LOD at render time.
|
||
#[derive(Clone, Debug)]
|
||
pub struct MeshLodSet {
|
||
pub lods: Vec<MeshModel>,
|
||
/// World XY AABB `[min_x, min_y, max_x, max_y]` of the mesh — used
|
||
/// by the per-frame LOD selector to compute the projected pixel
|
||
/// diagonal.
|
||
pub world_aabb: [f32; 4],
|
||
}
|
||
|
||
impl MeshLodSet {
|
||
/// Wrap a single MeshModel as a one-LOD set. Used by interactive
|
||
/// commands that only produce one tessellation (e.g. truck-based
|
||
/// BOX/CYLINDER creation). The LOD selector will pick slot 0 for
|
||
/// every zoom level.
|
||
pub fn from_single(mesh: MeshModel) -> Self {
|
||
let mut min_x = f32::INFINITY;
|
||
let mut min_y = f32::INFINITY;
|
||
let mut max_x = f32::NEG_INFINITY;
|
||
let mut max_y = f32::NEG_INFINITY;
|
||
for &[x, y, _] in &mesh.verts {
|
||
if !x.is_finite() || !y.is_finite() {
|
||
continue;
|
||
}
|
||
if x < min_x { min_x = x; }
|
||
if y < min_y { min_y = y; }
|
||
if x > max_x { max_x = x; }
|
||
if y > max_y { max_y = y; }
|
||
}
|
||
Self {
|
||
lods: vec![mesh],
|
||
world_aabb: [min_x, min_y, max_x, max_y],
|
||
}
|
||
}
|
||
}
|