From 397a19b40ea7740be7e3f4106fb56058232712ce Mon Sep 17 00:00:00 2001 From: Victor Giers Date: Mon, 27 Apr 2026 00:10:08 +0200 Subject: [PATCH] Track affected selection IDs for viewport updates --- src/viewport-three/viewport-host.ts | 85 ++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 3 deletions(-) diff --git a/src/viewport-three/viewport-host.ts b/src/viewport-three/viewport-host.ts index b1e736bc..aa2fa6ae 100644 --- a/src/viewport-three/viewport-host.ts +++ b/src/viewport-three/viewport-host.ts @@ -83,7 +83,8 @@ import type { ToolMode } from "../core/tool-mode"; import type { Vec3 } from "../core/vector"; import { createModelInstanceRenderGroup, - disposeModelInstance + disposeModelInstance, + syncModelInstanceSelectionShell } from "../assets/model-instance-rendering"; import type { LoadedModelAsset } from "../assets/gltf-model-import"; import type { LoadedImageAsset } from "../assets/image-assets"; @@ -341,6 +342,14 @@ interface ActiveTerrainBrushStroke { toolState: ArmedTerrainBrushState; } +interface AffectedSelectionIds { + brushIds: Set; + terrainIds: Set; + pathIds: Set; + entityIds: Set; + modelInstanceIds: Set; +} + interface ViewportWaterSurfaceBinding { brush: BoxBrush; reflectionTextureUniform: { value: unknown } | null; @@ -443,6 +452,69 @@ const WATER_REFLECTION_UPDATE_INTERVAL_MS = 96; const VIEWPORT_GRID_VISUAL_SIZE = 400; const VIEWPORT_GRID_VISUAL_DIVISIONS = 400; +function createAffectedSelectionIds(): AffectedSelectionIds { + return { + brushIds: new Set(), + terrainIds: new Set(), + pathIds: new Set(), + entityIds: new Set(), + modelInstanceIds: new Set() + }; +} + +function addSelectionAffectedIds( + affectedIds: AffectedSelectionIds, + selection: EditorSelection +) { + switch (selection.kind) { + case "none": + return; + case "brushes": + for (const brushId of selection.ids) { + affectedIds.brushIds.add(brushId); + } + return; + case "brushFace": + case "brushEdge": + case "brushVertex": + affectedIds.brushIds.add(selection.brushId); + return; + case "terrains": + for (const terrainId of selection.ids) { + affectedIds.terrainIds.add(terrainId); + } + return; + case "paths": + for (const pathId of selection.ids) { + affectedIds.pathIds.add(pathId); + } + return; + case "pathPoint": + affectedIds.pathIds.add(selection.pathId); + return; + case "entities": + for (const entityId of selection.ids) { + affectedIds.entityIds.add(entityId); + } + return; + case "modelInstances": + for (const modelInstanceId of selection.ids) { + affectedIds.modelInstanceIds.add(modelInstanceId); + } + return; + } +} + +function collectAffectedSelectionIds( + previousSelection: EditorSelection, + nextSelection: EditorSelection +): AffectedSelectionIds { + const affectedIds = createAffectedSelectionIds(); + addSelectionAffectedIds(affectedIds, previousSelection); + addSelectionAffectedIds(affectedIds, nextSelection); + return affectedIds; +} + interface CachedMaterialTexture { signature: string; textureSet: StarterMaterialTextureSet; @@ -887,12 +959,17 @@ export class ViewportHost { } updateSelection(selection: EditorSelection, activeSelectionId: string | null) { + const previousSelection = this.currentSelection; const selectionChanged = !areEditorSelectionsEqual( - this.currentSelection, + previousSelection, selection ); const activeSelectionChanged = this.currentActiveSelectionId !== activeSelectionId; + const affectedIds = collectAffectedSelectionIds( + previousSelection, + selection + ); this.currentSelection = selection; this.currentActiveSelectionId = activeSelectionId; @@ -905,7 +982,9 @@ export class ViewportHost { this.setHoveredSelection({ kind: "none" }); - this.refreshSelectionPresentation(); + this.addCameraRigRailPreviewPathIds(affectedIds, previousSelection); + this.addCameraRigRailPreviewPathIds(affectedIds, selection); + this.refreshSelectionPresentation(affectedIds); } updateDocument(document: SceneDocument) {