graphic design tool
git clone https://git.lucas.co/cce-designer.git
perf(spreadsheet): read the colour and group columns once
geometry_to_spreadsheet_columns looked each point's colour and each
group's membership up by name; it reads the columns once now
(point_colors, AttribStore::group). With cce-ui's faster width pass, a
refill with a simnet selected at 57k points: 3.0 ms a frame to 1.6.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CLAUDE.md | 10 ++++++++++
src/app.rs | 7 +++++--
src/detail.rs | 6 ++++++
3 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/CLAUDE.md b/CLAUDE.md
index baf9599..3151802 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -3552,6 +3552,16 @@ markers (1.0) and the visualizers' copy and apply (1.0) are what is left,
with the point markers' duplicate check (0.8 of their 1.1). A fresh 8 MB
buffer a frame costs 0.2 ms, so reusing buffers was not worth it.
+**The spreadsheet's refill, every frame of a replay with it shown**
+(the same day): `geometry_to_spreadsheet_columns` read each point's colour
+and each group's membership by name (`color(p)`, `in_group(g, p)`); it
+reads the columns once now (`point_colors`, `AttribStore::group`). And
+cce-ui's `SheetColumn::max_chars`, the width pass the widget runs over
+every value of every column, is branch-free and spread over the columns
+on several threads for a large table. A refill with a simnet selected at
+57k points: 3.0 ms a frame to 1.6 — the evaluation of the selected node,
+which copies its state out of the cache, the 0.6 left.
+
**The markers are instanced** (the same day, cce-ui's
`SceneDraw::instances`): every kind — Show Point Markers, Show Vertex
Markers, the selected group's, the marked groups' and the spreadsheet
diff --git a/src/app.rs b/src/app.rs
index 385f125..0f2b992 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -7392,12 +7392,15 @@ pub(crate) fn geometry_to_spreadsheet_columns(geom: &Detail) -> (Vec<String>, Ve
let mut columns = Vec::with_capacity(headers.len());
columns.push(SheetColumn::Int((0..n as i64).collect()));
for g in &groups {
- columns.push(SheetColumn::Int((0..n).map(|p| geom.points().in_group(g, p) as i64).collect()));
+ // The membership found once: `in_group` at every point looked the
+ // group up by name each time, most of what the table cost a frame.
+ let members = geom.points().group(g).unwrap_or(&[]);
+ columns.push(SheetColumn::Int((0..n).map(|p| members.get(p).copied().unwrap_or(false) as i64).collect()));
}
for k in 0..3 {
columns.push(float(geom.positions().iter().map(|p| p[k]).collect()));
}
- let colors: Vec<[f32; 3]> = (0..n).map(|p| geom.color(p)).collect();
+ let colors = geom.point_colors();
for k in 0..3 {
columns.push(float(colors.iter().map(|c| c[k]).collect()));
}
diff --git a/src/detail.rs b/src/detail.rs
index 6a4dc2c..738d807 100644
--- a/src/detail.rs
+++ b/src/detail.rs
@@ -567,6 +567,12 @@ impl AttribStore {
}
}
+ /// A group's membership, an element a flag: what [`in_group`](Self::in_group)
+ /// reads, the group found once — for a reader walking every element.
+ pub fn group(&self, name: &str) -> Option<&[bool]> {
+ self.groups.get(name).map(Vec::as_slice)
+ }
+
pub fn in_group(&self, name: &str, i: usize) -> bool {
self.groups.get(name).and_then(|m| m.get(i)).copied().unwrap_or(false)
}