forked from 1b-agent/opencadstudio-upstream
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.
This commit is contained in:
1 parent
c599c2ba09
commit
627761b629
20 files changed
+624
-191
No files matched your search
+50
-29
@@ -119,11 +119,60 @@ pub struct OstTrackPoint {
|
||||
pub screen: Point,
|
||||
}
|
||||
|
||||
pub fn grid_overlay<'a>(
|
||||
grid: Vec<GridParams>,
|
||||
) -> Element<'a, Message> {
|
||||
canvas(GridCanvas { grid })
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.into()
|
||||
}
|
||||
|
||||
struct GridCanvas {
|
||||
grid: Vec<GridParams>,
|
||||
}
|
||||
|
||||
impl canvas::Program<Message> for GridCanvas {
|
||||
type State = ();
|
||||
|
||||
fn draw(
|
||||
&self,
|
||||
_state: &(),
|
||||
renderer: &iced::Renderer,
|
||||
_theme: &Theme,
|
||||
bounds: iced::Rectangle,
|
||||
_cursor: mouse::Cursor,
|
||||
) -> Vec<canvas::Geometry> {
|
||||
let mut frame = canvas::Frame::new(renderer, bounds.size());
|
||||
|
||||
for g in &self.grid {
|
||||
let gb = g.bounds;
|
||||
let cx0 = gb.x.max(0.0);
|
||||
let cy0 = gb.y.max(0.0);
|
||||
let cx1 = (gb.x + gb.width).min(bounds.width);
|
||||
let cy1 = (gb.y + gb.height).min(bounds.height);
|
||||
if cx1 <= cx0 || cy1 <= cy0 {
|
||||
continue;
|
||||
}
|
||||
let clip = iced::Rectangle {
|
||||
x: cx0,
|
||||
y: cy0,
|
||||
width: cx1 - cx0,
|
||||
height: cy1 - cy0,
|
||||
};
|
||||
frame.with_clip(clip, |f| {
|
||||
draw_grid(f, g.view_rot, g.eye, g.plane, gb, g.origin, g.axes)
|
||||
});
|
||||
}
|
||||
|
||||
vec![frame.into_geometry()]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn selection_overlay<'a>(
|
||||
selection: SelectionState,
|
||||
snap: Option<(Point, SnapType)>,
|
||||
grips: Vec<GripMarker>,
|
||||
grid: Vec<GridParams>,
|
||||
ucs_icon: Option<UcsIconParams>,
|
||||
ost_points: Vec<OstTrackPoint>,
|
||||
cursor_screen: Point,
|
||||
@@ -135,7 +184,6 @@ pub fn selection_overlay<'a>(
|
||||
selection,
|
||||
snap,
|
||||
grips,
|
||||
grid,
|
||||
ucs_icon,
|
||||
ost_points,
|
||||
cursor_screen,
|
||||
@@ -152,7 +200,6 @@ struct SelectionCanvas {
|
||||
selection: SelectionState,
|
||||
snap: Option<(Point, SnapType)>,
|
||||
grips: Vec<GripMarker>,
|
||||
grid: Vec<GridParams>,
|
||||
ucs_icon: Option<UcsIconParams>,
|
||||
ost_points: Vec<OstTrackPoint>,
|
||||
cursor_screen: Point,
|
||||
@@ -313,32 +360,6 @@ impl canvas::Program<Message> for SelectionCanvas {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Grid display ──────────────────────────────────────────────────
|
||||
// One entry per pane with its grid on. Each is clipped to its own
|
||||
// rectangle so lines never spill into neighbouring panes — and the clip
|
||||
// is intersected with the widget so a zoomed-in viewport whose rectangle
|
||||
// overflows the canvas never paints grid outside the 3-D view.
|
||||
for g in &self.grid {
|
||||
let gb = g.bounds;
|
||||
let cx0 = gb.x.max(0.0);
|
||||
let cy0 = gb.y.max(0.0);
|
||||
let cx1 = (gb.x + gb.width).min(bounds.width);
|
||||
let cy1 = (gb.y + gb.height).min(bounds.height);
|
||||
if cx1 <= cx0 || cy1 <= cy0 {
|
||||
continue;
|
||||
}
|
||||
let clip = iced::Rectangle {
|
||||
x: cx0,
|
||||
y: cy0,
|
||||
width: cx1 - cx0,
|
||||
height: cy1 - cy0,
|
||||
};
|
||||
// Project with the full viewport rect `gb` so the grid stays aligned;
|
||||
// only the clip is clamped.
|
||||
frame.with_clip(clip, |f| {
|
||||
draw_grid(f, g.view_rot, g.eye, g.plane, gb, g.origin, g.axes)
|
||||
});
|
||||
}
|
||||
|
||||
if let (Some(a), Some(b)) = (self.selection.box_anchor, self.selection.box_current) {
|
||||
let (fill, stroke) = if self.selection.box_crossing {
|
||||
|
||||
Reference in new issue
Block a user