fix(block-cache): emit one greek substitute per source MTEXT entity

Colour-split MTEXT produces one outline wire per inline \C/\c override. At <5px zoom each outline independently emitted the full OBB greek rectangle — N overlapping boxes with last-colour-wins. Track last_lod_obb and skip duplicate substitutes.

Also corrects the fill-only LOD bypass: suppress fill-only wires at <5px instead of sending them unconditionally through emit_wire. The outline sibling's baseline or greek box suffices at sub-pixel zoom.
This commit is contained in:
Karim Jerbi committed 2026-06-28 19:17:24 +01:00
1 parent ca6239a32d
commit ae2946a8a9
1 file changed
+33 -16
+33 -16
View File
@@ -1083,6 +1083,12 @@ fn expand_defn(
eprintln!("block_cache: nested-block depth > {MAX_NESTING_DEPTH}, truncating");
return;
}
// Track the last text OBB that received a LOD substitute (baseline line
// or greeked box). Colour-split MTEXT produces one outline wire per
// \C/\c segment; only the first outline from a source entity should
// emit the substitute — subsequent segments use the same full-document
// OBB and would draw overlapping rectangles with the wrong colour.
let mut last_lod_obb: Option<[[f64; 3]; 4]> = None;
for sub in &defn.subs {
match sub {
LocalSub::Wire(lw) => {
@@ -1114,27 +1120,38 @@ fn expand_defn(
// We apply the Insert's transform scale to the stored
// local glyph height to get the screen height.
if let Some(h_local) = lw.text_height_local {
// Fill-only wires (outline stripped into a sibling
// LocalWire) must bypass the LOD ladder: both
// emit_text_baseline and emit_greeked_text generate
// their own OBB geometry and completely ignore
// lw.fill_tris, so routing a fill-only wire through
// either path would produce an invisible double-draw.
// emit_wire handles fill_tris correctly at all zoom
// levels, so skip the LOD rungs for these wires.
if !lw.is_fill_only {
let m = &accum_xform.matrix.m;
let sy = ((m[1][0] * m[1][0]
+ m[1][1] * m[1][1]
+ m[1][2] * m[1][2]) as f64)
.sqrt() as f32;
let h_world = h_local * sy;
let h_px = h_world / wpp;
let m = &accum_xform.matrix.m;
let sy = ((m[1][0] * m[1][0]
+ m[1][1] * m[1][1]
+ m[1][2] * m[1][2]) as f64)
.sqrt() as f32;
let h_world = h_local * sy;
let h_px = h_world / wpp;
if lw.is_fill_only {
// Fill-only wire: suppress at text LOD thresholds.
// The outline sibling carries the LOD substitute
// (baseline line or greeked box). Emitting every
// glyph triangle at sub-pixel zoom defeats the
// purpose of the LOD ladder.
if h_px < 5.0 {
continue;
}
} else {
if h_px < 1.0 {
emit_text_baseline(lw, accum_xform, ctx, out, wpp);
continue;
}
if h_px < 5.0 {
// Colour-split MTEXT: only the first outline
// wire from a source entity emits the greek
// substitute. Subsequent segments share the
// same text_obb_local and would draw
// overlapping rectangles with the wrong
// (last-wins) colour.
if lw.text_obb_local == last_lod_obb {
continue;
}
last_lod_obb = lw.text_obb_local;
emit_greeked_text(lw, local, accum_xform, ctx, out);
continue;
}