feat: adapt white/black entity colors to background luminance

White entities on light backgrounds (e.g. paper space) render as black;
black entities on dark backgrounds (e.g. model space) render as white.
All other colors pass through unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
HakanandClaude Sonnet 4.6 committed 2026-04-30 10:00:46 +03:00
1 parent 7065bfa935
commit d06db45950
2 files changed
+27 -3

No files matched your search

+8 -2
View File
@@ -621,9 +621,10 @@ impl Scene {
// Paper-space entities live in sheet coordinates (mm), not model-world
// coordinates, so world_offset must not be subtracted from them.
let woff = if self.current_layout == "Model" { self.world_offset } else { [0.0; 3] };
let bg = if self.current_layout == "Model" { self.bg_color } else { self.paper_bg_color };
let mut wires: Vec<WireModel> = visible
.into_par_iter()
.flat_map(|e| tessellate_entity(doc, sel, avp, woff, e))
.flat_map(|e| tessellate_entity(doc, sel, avp, woff, bg, e))
.collect();
// Apply draw order via the cached index (O(1) block lookup).
@@ -681,7 +682,8 @@ impl Scene {
/// Full tessellation pipeline for one entity.
fn tessellate_one(&self, e: &EntityType) -> Vec<WireModel> {
tessellate_entity(&self.document, &self.selected, self.active_viewport, self.world_offset, e)
let bg = if self.current_layout == "Model" { self.bg_color } else { self.paper_bg_color };
tessellate_entity(&self.document, &self.selected, self.active_viewport, self.world_offset, bg, e)
}
fn model_space_block_handle(&self) -> Handle {
@@ -2709,6 +2711,7 @@ fn tessellate_entity(
selected: &HashSet<Handle>,
active_viewport: Option<Handle>,
world_offset: [f64; 3],
bg_color: [f32; 4],
e: &EntityType,
) -> Vec<WireModel> {
let h = e.common().handle;
@@ -2742,6 +2745,7 @@ fn tessellate_entity(
let (entity_color, pattern_length, pattern, line_weight_px, aci) =
render::render_style_for(document, e);
let entity_color = render::adapt_to_bg(entity_color, bg_color);
let lt_scale = e.common().linetype_scale as f32;
let lt_name = render::linetype_name_for(document, e);
@@ -2762,6 +2766,7 @@ fn tessellate_entity(
// Resolve the INSERT's own style so ByBlock sub-entities can inherit it.
let (ins_color, ins_pat_len, ins_pat, ins_lw_px, _) =
render::render_style_for(document, e);
let ins_color = render::adapt_to_bg(ins_color, bg_color);
return ins
.explode_from_document(document)
.iter()
@@ -2774,6 +2779,7 @@ fn tessellate_entity(
document, &sub,
ins_color, ins_pat_len, ins_pat, ins_lw_px,
);
let sub_color = render::adapt_to_bg(sub_color, bg_color);
let sub_aabb = entity_aabb(&sub, world_offset);
let mut wire = tessellate::tessellate(
document,
+19 -1
View File
@@ -161,7 +161,9 @@ impl shader::Primitive for Primitive {
impl Scene {
/// Returns (entity_color, pattern_length, pattern, line_weight_px, aci).
pub(super) fn render_style(&self, e: &EntityType) -> ([f32; 4], f32, [f32; 8], f32, u8) {
render_style_for(&self.document, e)
let (color, pl, pat, lw, aci) = render_style_for(&self.document, e);
let bg = if self.current_layout == "Model" { self.bg_color } else { self.paper_bg_color };
(adapt_to_bg(color, bg), pl, pat, lw, aci)
}
}
@@ -269,6 +271,22 @@ pub(super) fn render_style_for_block_sub(
(final_color, final_pat_len, final_pat, final_lw, aci)
}
/// Adapt white→black or black→white based on background luminance.
/// White entities on light backgrounds become black, black entities on dark
/// backgrounds become white. All other colors pass through unchanged.
pub(super) fn adapt_to_bg(color: [f32; 4], bg: [f32; 4]) -> [f32; 4] {
let lum = 0.299 * bg[0] + 0.587 * bg[1] + 0.114 * bg[2];
let is_white = color[0] > 0.95 && color[1] > 0.95 && color[2] > 0.95;
let is_black = color[0] < 0.05 && color[1] < 0.05 && color[2] < 0.05;
if is_white && lum > 0.5 {
[0.0, 0.0, 0.0, color[3]]
} else if is_black && lum <= 0.5 {
[1.0, 1.0, 1.0, color[3]]
} else {
color
}
}
// ── Primitive builder helpers (called by ViewportPane's shader::Program impl) ──
impl Scene {