Viewport: keep the model scene in blocks and upload only what changed (#1147) (#1154)

* Viewport: keep the model scene in blocks and upload only what changed

Every change rebuilt the whole model scene (every body's triangles and edges) and
uploaded all of it again, so a design an agent builds one body at a time paid for the
whole model on every command. The scene is now built in blocks of a few bodies, cut
where a body's own key says, and each block's bytes and GPU buffers are kept while the
block comes back unchanged. Body boxes (fit, picking, ground shadow) are kept per mesh.

Rendering is unchanged: the bicycle from bench-agent opens to a byte-identical
screenshot.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Browser: find an occurrence's placed bodies by name, not by search per row

Each body row of a placed component searched the placement's bodies for its own, every
frame: quadratic in the component's bodies (720 for the bench-agent bicycle's hardware).

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
This commit is contained in:
bherbruckandClaude Opus 5.5 authored and GitHub committed 2026-10-14 14:32:32 -04:00
1 parent 9b0f028f13
commit 39bc87a8cc
5 files changed
+278 -60

No files matched your search

+7 -1
View File
@@ -1374,9 +1374,15 @@ fn folder_rows_at(app: &mut SolveApp, ui: &mut egui::Ui, comp: u64, path: Option
let prefix = path.map(occurrence_key).unwrap_or_else(|| format!("c{comp}"));
if let Some(path) = path {
let Ok(placement) = app.session.occurrence_placement(path) else { return };
// Each row's placed body by its definition's name (a search per row was quadratic in a
// component's bodies, every frame).
let mut placed: std::collections::HashMap<&str, &_> = std::collections::HashMap::with_capacity(placement.bodies.len());
for b in &placement.bodies {
placed.entry(b.source.as_str()).or_insert(b);
}
for e in &mut all {
if folder == "bodies" {
let Some(body) = placement.bodies.iter().find(|b| b.source == e.key) else { continue };
let Some(body) = placed.get(e.key.as_str()) else { continue };
e.sel = Some(Sel::Body { name: body.world.clone() });
e.target = Some(Target::Body { name: body.world.clone() });
e.bodies = vec![body.world.clone()];