cad-editor/src/scene/convert/acad_to_truck.rs
Karim Jerbi 627761b629 fix(text): render TTF glyphs as solid fills, fix font fallback, correct Z-order
Text elements previously rendered as hollow wireframe outlines and sometimes
fell back to the wrong system font due to case-sensitive exact matching. Also,
the viewport background grid drew on top of solid entities.

Case-insensitive and partial-name fallback matching (e.g., mapping "arialn"
to "Arial Narrow") is now added to `sysfont::canonical_family_name`, ensuring
text resolves to the correct installed system font.

TrueType font contours are now triangulated into solid fills (`fill_tris`)
using `lyon_tessellation` in `ttf_glyph.rs`. To prevent the GPU from misclassifying
this 2D text as a 3D mesh (which broke flat shading), text tessellation splits
the output into separate outline and fill `WireModel`s.

The background grid is extracted from `SelectionCanvas` into `GridCanvas` and
moved beneath the 3D viewport to ensure proper layering. Finally, `DepthBiasState`
is enabled on all face/fill pipelines to apply a polygon offset, perfectly
resolving Z-fighting between coplanar wireframe lines and solid faces.
2026-06-25 18:17:01 +01:00

56 lines
2.2 KiB
Rust

// acadrust -> truck topology conversion layer.
use acadrust::{CadDocument, EntityType};
use truck_modeling::{Edge, Solid, Vertex, Wire};
use crate::entities::traits::EntityTypeOps;
use crate::scene::model::wire_model::{SnapHint, TangentGeom};
/// One group of glyph strokes with its world-space origin stored in f64.
/// Strokes are in glyph-local space (origin = [0,0]) so that the large
/// world offset can be subtracted with f64 precision in tessellate.rs.
///
/// `color`, when set, overrides the entity colour for just this group — used
/// by MTEXT inline `\C` / `\c` per-run colour. Strokes sharing the same
/// (color, None) override are merged into one WireModel downstream; runs with
/// distinct colours emit their own WireModel.
pub struct TextStroke {
pub strokes: Vec<Vec<[f32; 2]>>,
pub origin: [f64; 2],
pub color: Option<[f32; 3]>,
pub fill_tris: Vec<[f32; 2]>,
}
#[allow(dead_code)]
pub enum TruckObject {
Point(Vertex),
Curve(Edge),
Contour(Wire),
Text(Vec<TextStroke>),
/// Pre-computed NaN-separated 3-D point list (leader lines, arrowheads, etc.).
/// Points are stored in WCS as **f64** so the large world_offset can be
/// subtracted in full precision in tessellate.rs before the f32 cast.
/// Casting WCS coordinates to f32 in the entity converters used to wreck
/// rotated sub-glyph precision on drawings far from origin.
Lines(Vec<[f64; 3]>),
/// Like Lines but linetype pattern restarts at each NaN-separated segment (plinegen=false).
SegmentedLines(Vec<[f64; 3]>),
Volume(Solid),
}
pub struct TruckEntity {
pub object: TruckObject,
pub snap_pts: Vec<(glam::DVec3, SnapHint)>,
pub tangent_geoms: Vec<TangentGeom>,
/// Polyline vertex positions in WCS f64; converted to offset-relative f32
/// at the wire-model boundary.
pub key_vertices: Vec<[f64; 3]>,
/// Pre-triangulated fill geometry: flat list of WCS f64 vertices, 3 per
/// triangle. Non-empty for mesh-like entities (PolyfaceMesh, PolygonMesh)
/// that need solid fill.
pub fill_tris: Vec<[f64; 3]>,
}
pub fn convert(entity: &EntityType, document: &CadDocument) -> Option<TruckEntity> {
entity.to_truck_entity(document)
}