forked from 1b-agent/opencadstudio-upstream
perf(scene): greek top-level Text/MText below 4px height
When a Text/MText entity's anno-scaled glyph height projects to fewer than 4 screen pixels, drop the per-glyph stroke tessellation and emit a single filled rectangle in the text's color instead. The user still sees "text lives here" at the original color and footprint, but the expensive font-stroke generation is skipped for thousands of unreadable labels at fit-all / zoom-out views. Pre-boosts the fill color to compensate for the 0.45 ambient-occlusion dim the face3d pipeline applies (it's meant for 3D-shaded mesh solids, not 2D text greeking). Note: applies only to top-level entities; Text/MText *inside* block defs is already tessellated into the block cache at build time, so greeking those would require either a cache rebuild on zoom or a parallel "low-detail" cache. Left for later if real-world test suggests it's needed. Co-Authored-By: Claude Opus 4.7 <[email protected]>
This commit is contained in:
1 parent
c5ed83c752
commit
242e8870c3
1 file changed
+67
-1
+67
-1
@@ -3901,7 +3901,8 @@ fn tessellate_entity(
|
||||
if let Some(wpp) = world_per_pixel {
|
||||
let w = (ab[2] - ab[0]).abs();
|
||||
let h = (ab[3] - ab[1]).abs();
|
||||
if w.max(h) / wpp < 0.5 {
|
||||
// Keep in sync with `block_cache::MIN_PIXEL_SIZE`.
|
||||
if w.max(h) / wpp < 5.0 {
|
||||
return vec![];
|
||||
}
|
||||
}
|
||||
@@ -4102,6 +4103,71 @@ fn tessellate_entity(
|
||||
}
|
||||
|
||||
let aabb = entity_aabb(e, world_offset);
|
||||
|
||||
// Text greeking: when a Text/MText entity's projected glyph height
|
||||
// drops below a readable size, replace the per-glyph stroke geometry
|
||||
// with a single filled rectangle in the text's color. Same visual
|
||||
// hint ("text lives here") at a fraction of the tessellation cost.
|
||||
if let Some(wpp) = world_per_pixel {
|
||||
let text_height: Option<f64> = match e {
|
||||
EntityType::Text(t) => Some(t.height * anno_scale as f64),
|
||||
EntityType::MText(m) => Some(m.height * anno_scale as f64),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(h_world) = text_height {
|
||||
let h_px = (h_world as f32) / wpp;
|
||||
// < 4 px: glyphs aren't readable; emit a greeked rect instead.
|
||||
// We still drew through the LOD floor (entity AABB > 2 px), so
|
||||
// this rect is bigger than 2 px in at least one dimension.
|
||||
if h_px < 4.0 && aabb != WireModel::UNBOUNDED_AABB {
|
||||
let [x0, y0, x1, y1] = aabb;
|
||||
let z = match e {
|
||||
EntityType::Text(t) => (t.insertion_point.z - world_offset[2]) as f32,
|
||||
EntityType::MText(m) => (m.insertion_point.z - world_offset[2]) as f32,
|
||||
_ => 0.0,
|
||||
};
|
||||
// Two CCW triangles spanning the AABB.
|
||||
let fill_tris = vec![
|
||||
[x0, y0, z],
|
||||
[x1, y0, z],
|
||||
[x1, y1, z],
|
||||
[x0, y0, z],
|
||||
[x1, y1, z],
|
||||
[x0, y1, z],
|
||||
];
|
||||
// The face3d pipeline dims fill_tris colors to 45% to fake
|
||||
// ambient occlusion on PolyfaceMesh / 3DFACE solids. Greeked
|
||||
// text doesn't want that shading — pre-boost the color so it
|
||||
// emerges close to the original text color after the dim.
|
||||
let boost = 1.0 / 0.45;
|
||||
let [r, g, b, a] = entity_color;
|
||||
let greek_color = [
|
||||
(r * boost).min(1.0),
|
||||
(g * boost).min(1.0),
|
||||
(b * boost).min(1.0),
|
||||
a,
|
||||
];
|
||||
return vec![WireModel {
|
||||
name: h.value().to_string(),
|
||||
points: vec![],
|
||||
color: greek_color,
|
||||
selected: sel,
|
||||
aci,
|
||||
pattern_length: 0.0,
|
||||
pattern: [0.0; 8],
|
||||
line_weight_px: 1.0,
|
||||
snap_pts: vec![],
|
||||
tangent_geoms: vec![],
|
||||
key_vertices: vec![],
|
||||
aabb,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris,
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut base = tessellate::tessellate(
|
||||
document,
|
||||
h,
|
||||
|
||||
Reference in new issue
Block a user