diff --git a/src/layer/segmentation/index.spec.ts b/src/layer/segmentation/index.spec.ts index 95bc1b937..55225e041 100644 --- a/src/layer/segmentation/index.spec.ts +++ b/src/layer/segmentation/index.spec.ts @@ -25,8 +25,6 @@ const { SegmentationUserLayer } = await import( const { PerspectiveViewSpatiallyIndexedSkeletonLayer, SliceViewPanelSpatiallyIndexedSkeletonLayer, - SliceViewSpatiallyIndexedSkeletonLayer, - MultiscaleSliceViewSpatiallyIndexedSkeletonLayer, } = await import("#src/skeleton/frontend.js"); const { SegmentSelectionState } = await import( @@ -81,30 +79,14 @@ function makeSpatialSkeletonLayerWithSource(source: unknown) { describe("layer/segmentation spatial skeleton chunk stats", () => { it("tracks combined chunk load state from the loading render layers only", () => { + // After the 2D/3D backend unification, only PerspectiveViewSpatiallyIndexedSkeletonLayer + // contributes to the chunk stats (it handles both 2D and 3D views via the shared backend). const perspectiveLayer = Object.assign( Object.create(PerspectiveViewSpatiallyIndexedSkeletonLayer.prototype), { layerChunkProgressInfo: { - numVisibleChunksNeeded: 5, - numVisibleChunksAvailable: 3, - }, - }, - ); - const sliceLayer = Object.assign( - Object.create(SliceViewSpatiallyIndexedSkeletonLayer.prototype), - { - layerChunkProgressInfo: { - numVisibleChunksNeeded: 4, - numVisibleChunksAvailable: 2, - }, - }, - ); - const multiscaleSliceLayer = Object.assign( - Object.create(MultiscaleSliceViewSpatiallyIndexedSkeletonLayer.prototype), - { - layerChunkProgressInfo: { - numVisibleChunksNeeded: 6, - numVisibleChunksAvailable: 5, + numVisibleChunksNeeded: 9, + numVisibleChunksAvailable: 7, }, }, ); @@ -121,12 +103,7 @@ describe("layer/segmentation spatial skeleton chunk stats", () => { const layer = Object.assign( Object.create(SegmentationUserLayer.prototype), { - renderLayers: [ - perspectiveLayer, - sliceLayer, - multiscaleSliceLayer, - slicePanelLayer, - ], + renderLayers: [perspectiveLayer, slicePanelLayer], spatialSkeletonVisibleChunksNeeded: new WatchableValue(0), spatialSkeletonVisibleChunksAvailable: new WatchableValue(0), spatialSkeletonVisibleChunksLoaded: new WatchableValue(false), @@ -136,8 +113,8 @@ describe("layer/segmentation spatial skeleton chunk stats", () => { layer.updateSpatialSkeletonChunkLoadState(); - expect(layer.spatialSkeletonVisibleChunksNeeded.value).toBe(15); - expect(layer.spatialSkeletonVisibleChunksAvailable.value).toBe(10); + expect(layer.spatialSkeletonVisibleChunksNeeded.value).toBe(9); + expect(layer.spatialSkeletonVisibleChunksAvailable.value).toBe(7); expect(layer.spatialSkeletonVisibleChunksLoaded.value).toBe(false); }); }); diff --git a/src/layer/segmentation/index.ts b/src/layer/segmentation/index.ts index 9311d453e..10b413058 100644 --- a/src/layer/segmentation/index.ts +++ b/src/layer/segmentation/index.ts @@ -128,11 +128,9 @@ import { SliceViewPanelSkeletonLayer, PerspectiveViewSpatiallyIndexedSkeletonLayer, SliceViewPanelSpatiallyIndexedSkeletonLayer, - SliceViewSpatiallyIndexedSkeletonLayer, SpatiallyIndexedSkeletonLayer, SpatiallyIndexedSkeletonSource, MultiscaleSpatiallyIndexedSkeletonSource, - MultiscaleSliceViewSpatiallyIndexedSkeletonLayer, } from "#src/skeleton/frontend.js"; import { classifySpatialSkeletonDisplayNodeType as getSpatialSkeletonDisplayNodeType, @@ -1409,8 +1407,7 @@ export class SegmentationUserLayer extends Base { !layers.some( (layer) => (layer instanceof PerspectiveViewSpatiallyIndexedSkeletonLayer || - layer instanceof SliceViewPanelSpatiallyIndexedSkeletonLayer || - layer instanceof SliceViewSpatiallyIndexedSkeletonLayer) && + layer instanceof SliceViewPanelSpatiallyIndexedSkeletonLayer) && getSpatiallyIndexedSkeletonSource(layer.base) !== undefined, ), { changed: this.layersChanged, value: this.renderLayers }, @@ -1510,30 +1507,18 @@ export class SegmentationUserLayer extends Base { if (layer instanceof SliceViewPanelSpatiallyIndexedSkeletonLayer) { return layer.base; } - if (layer instanceof SliceViewSpatiallyIndexedSkeletonLayer) { - return layer.base; - } } return undefined; }; getSpatialSkeletonChunkStats(kind: "2d" | "3d") { + // 2D chunks are now handled by the same backend as 3D, so only report + // under "3d" to avoid double-counting in updateSpatialSkeletonChunkLoadState. + if (kind === "2d") return { presentCount: 0, totalCount: 0 }; let needed = 0; let available = 0; for (const layer of this.renderLayers) { - if ( - kind === "3d" && - layer instanceof PerspectiveViewSpatiallyIndexedSkeletonLayer - ) { - needed += layer.layerChunkProgressInfo.numVisibleChunksNeeded; - available += layer.layerChunkProgressInfo.numVisibleChunksAvailable; - continue; - } - if ( - kind === "2d" && - (layer instanceof SliceViewSpatiallyIndexedSkeletonLayer || - layer instanceof MultiscaleSliceViewSpatiallyIndexedSkeletonLayer) - ) { + if (layer instanceof PerspectiveViewSpatiallyIndexedSkeletonLayer) { needed += layer.layerChunkProgressInfo.numVisibleChunksNeeded; available += layer.layerChunkProgressInfo.numVisibleChunksAvailable; } @@ -1568,8 +1553,7 @@ export class SegmentationUserLayer extends Base { for (const layer of this.renderLayers) { if ( layer instanceof PerspectiveViewSpatiallyIndexedSkeletonLayer || - layer instanceof SliceViewPanelSpatiallyIndexedSkeletonLayer || - layer instanceof SliceViewSpatiallyIndexedSkeletonLayer + layer instanceof SliceViewPanelSpatiallyIndexedSkeletonLayer ) { hasSpatialSkeletonLayer = true; break; @@ -1587,8 +1571,7 @@ export class SegmentationUserLayer extends Base { for (const layer of this.renderLayers) { if ( layer instanceof PerspectiveViewSpatiallyIndexedSkeletonLayer || - layer instanceof SliceViewPanelSpatiallyIndexedSkeletonLayer || - layer instanceof SliceViewSpatiallyIndexedSkeletonLayer + layer instanceof SliceViewPanelSpatiallyIndexedSkeletonLayer ) { return layer.base.source; } @@ -1802,13 +1785,6 @@ export class SegmentationUserLayer extends Base { ), ); } else if (mesh instanceof MultiscaleSpatiallyIndexedSkeletonSource) { - const base = new MultiscaleSliceViewSpatiallyIndexedSkeletonLayer( - this.manager.chunkManager, - mesh, - displayState, - ); - loadedSubsource.addRenderLayer(base); - const perspectiveSources = mesh.getPerspectiveSources(); const slicePanelSources = mesh.getSliceViewPanelSources(); const sharedSpatialSkeletonSources = @@ -1825,6 +1801,8 @@ export class SegmentationUserLayer extends Base { { gridLevel: displayState.spatialSkeletonGridLevel3d, lod: displayState.skeletonLod, + gridLevel2d: displayState.spatialSkeletonGridLevel2d, + lod2d: displayState.spatialSkeletonLod2d, sources2d: slicePanelSources, selectedNodeId: this.selectedSpatialSkeletonNodeId, pendingNodePositionVersion: @@ -1861,6 +1839,8 @@ export class SegmentationUserLayer extends Base { { gridLevel: displayState.spatialSkeletonGridLevel3d, lod: displayState.skeletonLod, + gridLevel2d: displayState.spatialSkeletonGridLevel2d, + lod2d: displayState.spatialSkeletonLod2d, selectedNodeId: this.selectedSpatialSkeletonNodeId, pendingNodePositionVersion: this.spatialSkeletonState.pendingNodePositionVersion, @@ -1874,9 +1854,6 @@ export class SegmentationUserLayer extends Base { loadedSubsource.addRenderLayer( new PerspectiveViewSpatiallyIndexedSkeletonLayer(base.addRef()), ); - loadedSubsource.addRenderLayer( - new SliceViewSpatiallyIndexedSkeletonLayer(base.addRef()), - ); loadedSubsource.addRenderLayer( new SliceViewPanelSpatiallyIndexedSkeletonLayer( /* transfer ownership */ base, diff --git a/src/skeleton/backend.ts b/src/skeleton/backend.ts index a5deb22e6..def849509 100644 --- a/src/skeleton/backend.ts +++ b/src/skeleton/backend.ts @@ -43,7 +43,6 @@ import { SKELETON_LAYER_RPC_ID, SPATIALLY_INDEXED_SKELETON_RENDER_LAYER_RPC_ID, SPATIALLY_INDEXED_SKELETON_RENDER_LAYER_UPDATE_SOURCES_RPC_ID, - SPATIALLY_INDEXED_SKELETON_SLICEVIEW_RENDER_LAYER_RPC_ID, } from "#src/skeleton/base.js"; import { freeSkeletonChunkSystemMemory, @@ -61,11 +60,9 @@ import { SCALE_PRIORITY_MULTIPLIER, SliceViewChunk, SliceViewChunkSourceBackend, - SliceViewRenderLayerBackend, } from "#src/sliceview/backend.js"; import { forEachVisibleVolumetricChunk, - type SliceViewBase, type SliceViewChunkSpecification, type SliceViewProjectionParameters, type TransformedSource, @@ -368,6 +365,8 @@ export class SpatiallyIndexedSkeletonRenderLayerBackend extends withChunkManager renderScaleTarget: SharedWatchableValue; skeletonLod: SharedWatchableValue; skeletonGridLevel: SharedWatchableValue; + skeletonLod2d: SharedWatchableValue; + skeletonGridLevel2d: SharedWatchableValue; private pendingLodCleanup = false; constructor(rpc: RPC, options: any) { @@ -376,6 +375,8 @@ export class SpatiallyIndexedSkeletonRenderLayerBackend extends withChunkManager this.localPosition = rpc.get(options.localPosition); this.skeletonLod = rpc.get(options.skeletonLod); this.skeletonGridLevel = rpc.get(options.skeletonGridLevel); + this.skeletonLod2d = rpc.get(options.skeletonLod2d); + this.skeletonGridLevel2d = rpc.get(options.skeletonGridLevel2d); const scheduleUpdateChunkPriorities = () => this.chunkManager.scheduleUpdateChunkPriorities(); this.registerDisposer( @@ -387,6 +388,9 @@ export class SpatiallyIndexedSkeletonRenderLayerBackend extends withChunkManager this.registerDisposer( this.skeletonGridLevel.changed.add(scheduleUpdateChunkPriorities), ); + this.registerDisposer( + this.skeletonGridLevel2d.changed.add(scheduleUpdateChunkPriorities), + ); // Debounce LOD changes to avoid making requests for every slider value const debouncedLodUpdate = debounce(() => { @@ -394,12 +398,12 @@ export class SpatiallyIndexedSkeletonRenderLayerBackend extends withChunkManager }, SPATIALLY_INDEXED_SKELETON_LOD_DEBOUNCE_MS); this.registerDisposer(() => debouncedLodUpdate.cancel()); - this.registerDisposer( - this.skeletonLod.changed.add(() => { - this.pendingLodCleanup = true; - debouncedLodUpdate(); - }), - ); + const onLodChanged = () => { + this.pendingLodCleanup = true; + debouncedLodUpdate(); + }; + this.registerDisposer(this.skeletonLod.changed.add(onLodChanged)); + this.registerDisposer(this.skeletonLod2d.changed.add(onLodChanged)); this.registerDisposer( this.chunkManager.recomputeChunkPriorities.add(() => this.recomputeChunkPriorities(), @@ -514,7 +518,10 @@ export class SpatiallyIndexedSkeletonRenderLayerBackend extends withChunkManager } } const renderScaleTarget = this.renderScaleTarget.value; - const skeletonGridLevel = this.skeletonGridLevel.value; + const is2dView = pixelSize !== undefined; + const skeletonGridLevel = ( + is2dView ? this.skeletonGridLevel2d : this.skeletonGridLevel + ).value; const selectScales = ( scales: TransformedSource< @@ -606,7 +613,7 @@ export class SpatiallyIndexedSkeletonRenderLayerBackend extends withChunkManager return selected; }; - const lodValue = this.skeletonLod.value; + const lodValue = (is2dView ? this.skeletonLod2d : this.skeletonLod).value; for (const scales of transformedSources) { const selectedScales = selectScales(scales); for (const { tsource, scaleIndex } of selectedScales) { @@ -624,8 +631,9 @@ export class SpatiallyIndexedSkeletonRenderLayerBackend extends withChunkManager basePriority + SCALE_PRIORITY_MULTIPLIER * scaleIndex; source.currentLod = lodValue; source.currentRequestGeneration = currentGeneration; - source.currentRequestOwner = - SpatiallyIndexedSkeletonChunkRequestOwner.VIEW_3D; + source.currentRequestOwner = is2dView + ? SpatiallyIndexedSkeletonChunkRequestOwner.VIEW_2D + : SpatiallyIndexedSkeletonChunkRequestOwner.VIEW_3D; forEachVisibleVolumetricChunk( projectionParameters, this.localPosition.value, @@ -653,87 +661,3 @@ export class SpatiallyIndexedSkeletonRenderLayerBackend extends withChunkManager } } } - -@registerSharedObject(SPATIALLY_INDEXED_SKELETON_SLICEVIEW_RENDER_LAYER_RPC_ID) -export class SpatiallyIndexedSkeletonSliceViewRenderLayerBackend extends SliceViewRenderLayerBackend { - skeletonGridLevel: SharedWatchableValue; - skeletonLod: SharedWatchableValue; - private chunkManager_: ChunkManager; - private pendingLodCleanup = false; - private trackedSources = new Set(); - - constructor(rpc: RPC, options: any) { - super(rpc, options); - this.skeletonGridLevel = rpc.get(options.skeletonGridLevel); - this.skeletonLod = rpc.get(options.skeletonLod); - const chunkManager = rpc.get(options.chunkManager); - this.chunkManager_ = chunkManager; - const scheduleUpdateChunkPriorities = () => - chunkManager.scheduleUpdateChunkPriorities(); - this.registerDisposer( - this.skeletonGridLevel.changed.add(scheduleUpdateChunkPriorities), - ); - // Debounce LOD changes to avoid making requests for every slider value. - const debouncedLodUpdate = debounce(() => { - scheduleUpdateChunkPriorities(); - }, SPATIALLY_INDEXED_SKELETON_LOD_DEBOUNCE_MS); - this.registerDisposer(() => debouncedLodUpdate.cancel()); - - this.registerDisposer( - this.skeletonLod.changed.add(() => { - this.pendingLodCleanup = true; - debouncedLodUpdate(); - }), - ); - this.registerDisposer( - chunkManager.recomputeChunkPrioritiesLate.add(() => { - if (!this.pendingLodCleanup) return; - cancelStaleSpatiallyIndexedSkeletonDownloads( - chunkManager, - this.trackedSources, - chunkManager.recomputeChunkPriorities.count, - ); - this.pendingLodCleanup = false; - }), - ); - } - - prepareChunkSourceForRequest(source: SpatiallyIndexedSkeletonSourceBackend) { - this.trackedSources.add(source); - source.currentLod = this.skeletonLod.value; - source.currentRequestGeneration = - this.chunkManager_.recomputeChunkPriorities.count; - source.currentRequestOwner = - SpatiallyIndexedSkeletonChunkRequestOwner.VIEW_2D; - } - - filterVisibleSources( - sliceView: SliceViewBase, - sources: readonly TransformedSource[], - ): Iterable { - const lodValue = this.skeletonLod.value; - for (const tsource of sources) { - const source = tsource.source as SpatiallyIndexedSkeletonSourceBackend; - this.trackedSources.add(source); - source.currentLod = lodValue; - source.currentRequestGeneration = - this.chunkManager_.recomputeChunkPriorities.count; - source.currentRequestOwner = - SpatiallyIndexedSkeletonChunkRequestOwner.VIEW_2D; - } - - if ( - sources.length > 0 && - sources.every( - (source) => getSpatiallyIndexedSkeletonGridIndex(source) !== undefined, - ) - ) { - return selectSpatiallyIndexedSkeletonEntriesByGrid( - sources, - this.skeletonGridLevel.value, - getSpatiallyIndexedSkeletonGridIndex, - ); - } - return super.filterVisibleSources(sliceView, sources); - } -} diff --git a/src/skeleton/base.ts b/src/skeleton/base.ts index a848400a1..051e19f1a 100644 --- a/src/skeleton/base.ts +++ b/src/skeleton/base.ts @@ -22,8 +22,6 @@ export const SPATIALLY_INDEXED_SKELETON_RENDER_LAYER_RPC_ID = "skeleton/SpatiallyIndexedSkeletonRenderLayer"; export const SPATIALLY_INDEXED_SKELETON_RENDER_LAYER_UPDATE_SOURCES_RPC_ID = "skeleton/SpatiallyIndexedSkeletonRenderLayer.updateSources"; -export const SPATIALLY_INDEXED_SKELETON_SLICEVIEW_RENDER_LAYER_RPC_ID = - "skeleton/SpatiallyIndexedSkeletonSliceViewRenderLayer"; export interface VertexAttributeInfo { dataType: DataType; diff --git a/src/skeleton/frontend.ts b/src/skeleton/frontend.ts index a5d072365..e4bae5b71 100644 --- a/src/skeleton/frontend.ts +++ b/src/skeleton/frontend.ts @@ -41,7 +41,6 @@ import type { RenderLayerTransform, } from "#src/render_coordinate_transform.js"; import { getChunkTransformParameters } from "#src/render_coordinate_transform.js"; -import { RENDERED_VIEW_ADD_LAYER_RPC_ID } from "#src/render_layer_common.js"; import type { RenderScaleHistogram } from "#src/render_scale_statistics.js"; import type { RenderLayer, @@ -57,10 +56,7 @@ import { getVisibleSegments, getObjectKey, } from "#src/segmentation_display_state/base.js"; -import type { - SegmentationDisplayState3D, - SegmentationDisplayState, -} from "#src/segmentation_display_state/frontend.js"; +import type { SegmentationDisplayState3D } from "#src/segmentation_display_state/frontend.js"; import { forEachVisibleSegmentToDraw, registerRedrawWhenSegmentationDisplayState3DChanged, @@ -73,7 +69,6 @@ import { SKELETON_LAYER_RPC_ID, SPATIALLY_INDEXED_SKELETON_RENDER_LAYER_RPC_ID, SPATIALLY_INDEXED_SKELETON_RENDER_LAYER_UPDATE_SOURCES_RPC_ID, - SPATIALLY_INDEXED_SKELETON_SLICEVIEW_RENDER_LAYER_RPC_ID, } from "#src/skeleton/base.js"; import { uploadVertexAttributesToGPU } from "#src/skeleton/gpu_upload_utils.js"; import { buildSpatiallyIndexedSkeletonOverlayGeometry } from "#src/skeleton/overlay_geometry.js"; @@ -87,14 +82,12 @@ import { SkeletonRenderMode } from "#src/skeleton/render_mode.js"; import { getSpatiallyIndexedSkeletonGridIndex, getSpatiallyIndexedSkeletonSourceView, - selectSpatiallyIndexedSkeletonEntriesByGrid, selectSpatiallyIndexedSkeletonEntriesForView, type SpatiallyIndexedSkeletonView, } from "#src/skeleton/source_selection.js"; import { spatiallyIndexedSkeletonTextureAttributeSpecs } from "#src/skeleton/spatial_attribute_layout.js"; import { forEachVisibleVolumetricChunk, - type SliceViewBase, type SliceViewChunkSpecification, type TransformedSource, } from "#src/sliceview/base.js"; @@ -110,13 +103,9 @@ import { import type { SliceViewPanel } from "#src/sliceview/panel.js"; import type { SliceViewPanelRenderContext, - SliceViewRenderContext, SliceViewPanelReadyRenderContext, } from "#src/sliceview/renderlayer.js"; -import { - SliceViewPanelRenderLayer, - SliceViewRenderLayer, -} from "#src/sliceview/renderlayer.js"; +import { SliceViewPanelRenderLayer } from "#src/sliceview/renderlayer.js"; import type { WatchableValueInterface } from "#src/trackable_value.js"; import { makeCachedLazyDerivedWatchableValue, @@ -1692,82 +1681,14 @@ export abstract class MultiscaleSpatiallyIndexedSkeletonSource extends Multiscal } } -export class MultiscaleSliceViewSpatiallyIndexedSkeletonLayer extends SliceViewRenderLayer { - private renderOptions: ViewSpecificSkeletonRenderingOptions; - RPC_TYPE_ID = SPATIALLY_INDEXED_SKELETON_SLICEVIEW_RENDER_LAYER_RPC_ID; - constructor( - public chunkManager: ChunkManager, - public multiscaleSource: MultiscaleSpatiallyIndexedSkeletonSource, - public displayState: SegmentationDisplayState, - ) { - const spatialDisplayState = displayState as SegmentationDisplayState & - SpatialSkeletonDisplayState; - const anyDisplayState = displayState as any; - const renderScaleTarget = - anyDisplayState.renderScaleTarget as WatchableValueInterface; - const gridLevel2d = spatialDisplayState.spatialSkeletonGridLevel2d; - super(chunkManager, multiscaleSource, { - transform: anyDisplayState.transform, - localPosition: anyDisplayState.localPosition, - renderScaleTarget, - visibleSourcesInvalidation: - gridLevel2d === undefined ? [] : [gridLevel2d], - }); - this.renderOptions = anyDisplayState.skeletonRenderingOptions.params2d; - this.registerDisposer( - this.renderOptions.mode.changed.add(this.redrawNeeded.dispatch), - ); - this.registerDisposer( - this.renderOptions.lineWidth.changed.add(this.redrawNeeded.dispatch), - ); - const rpc = this.chunkManager.rpc!; - const lod2d = spatialDisplayState.spatialSkeletonLod2d; - if (gridLevel2d !== undefined && lod2d !== undefined) { - this.rpcTransfer = { - ...this.rpcTransfer, - chunkManager: this.chunkManager.rpcId, - skeletonGridLevel: this.registerDisposer( - SharedWatchableValue.makeFromExisting(rpc, gridLevel2d), - ).rpcId, - skeletonLod: this.registerDisposer( - SharedWatchableValue.makeFromExisting(rpc, lod2d), - ).rpcId, - }; - } - this.initializeCounterpart(); - } - - filterVisibleSources( - sliceView: SliceViewBase, - sources: readonly TransformedSource[], - ): Iterable { - const gridLevel = (this.displayState as any).spatialSkeletonGridLevel2d - ?.value as number | undefined; - if ( - gridLevel === undefined || - sources.length === 0 || - !sources.every( - (source) => getSpatiallyIndexedSkeletonGridIndex(source) !== undefined, - ) - ) { - return super.filterVisibleSources(sliceView, sources); - } - return selectSpatiallyIndexedSkeletonEntriesByGrid( - sources, - gridLevel, - getSpatiallyIndexedSkeletonGridIndex, - ); - } - - draw(_renderContext: SliceViewRenderContext) {} -} - type SpatiallyIndexedSkeletonSourceEntry = SliceViewSingleResolutionSource; interface SpatiallyIndexedSkeletonLayerOptions { gridLevel?: WatchableValueInterface; lod?: WatchableValueInterface; + gridLevel2d?: WatchableValueInterface; + lod2d?: WatchableValueInterface; sources2d?: SpatiallyIndexedSkeletonSourceEntry[]; selectedNodeId?: WatchableValueInterface; pendingNodePositionVersion?: WatchableValueInterface; @@ -1940,6 +1861,8 @@ export class SpatiallyIndexedSkeletonLayer >(); gridLevel: WatchableValueInterface; lod: WatchableValueInterface; + gridLevel2d: WatchableValueInterface; + lod2d: WatchableValueInterface; private selectedNodeId: | WatchableValueInterface | undefined; @@ -2340,6 +2263,12 @@ export class SpatiallyIndexedSkeletonLayer new WatchableValue(0); this.lod = options.lod ?? spatialDisplayState.skeletonLod ?? new WatchableValue(0); + this.gridLevel2d = + options.gridLevel2d ?? + spatialDisplayState.spatialSkeletonGridLevel2d ?? + this.gridLevel; + this.lod2d = + options.lod2d ?? spatialDisplayState.spatialSkeletonLod2d ?? this.lod; this.selectedNodeId = options.selectedNodeId; this.pendingNodePositionVersion = options.pendingNodePositionVersion; this.getPendingNodePositionOverride = options.getPendingNodePosition; @@ -2430,6 +2359,14 @@ export class SpatiallyIndexedSkeletonLayer SharedWatchableValue.makeFromExisting(rpc, this.gridLevel), ); + const skeletonLod2dWatchable = this.registerDisposer( + SharedWatchableValue.makeFromExisting(rpc, this.lod2d), + ); + + const skeletonGridLevel2dWatchable = this.registerDisposer( + SharedWatchableValue.makeFromExisting(rpc, this.gridLevel2d), + ); + sharedObject.initializeCounterpart(rpc, { chunkManager: chunkManager.rpcId, localPosition: this.registerDisposer( @@ -2438,6 +2375,8 @@ export class SpatiallyIndexedSkeletonLayer renderScaleTarget: renderScaleTargetWatchable.rpcId, skeletonLod: skeletonLodWatchable.rpcId, skeletonGridLevel: skeletonGridLevelWatchable.rpcId, + skeletonLod2d: skeletonLod2dWatchable.rpcId, + skeletonGridLevel2d: skeletonGridLevel2dWatchable.rpcId, }); this.backend = sharedObject; } @@ -3140,16 +3079,6 @@ export class PerspectiveViewSpatiallyIndexedSkeletonLayer extends PerspectiveVie ) { super.attach(attachment); - // Manually add layer to backend - const backend = this.backend; - if (backend && backend.rpc) { - backend.rpc.invoke(RENDERED_VIEW_ADD_LAYER_RPC_ID, { - layer: backend.rpcId, - view: attachment.view.rpcId, - }); - } - - // Capture references to avoid losing 'this' context in callback const baseLayer = this.base; const redrawNeeded = this.redrawNeeded; @@ -3376,62 +3305,16 @@ export class PerspectiveViewSpatiallyIndexedSkeletonLayer extends PerspectiveVie } } -export class SliceViewSpatiallyIndexedSkeletonLayer extends SliceViewRenderLayer { - private renderOptions: ViewSpecificSkeletonRenderingOptions; - constructor(public base: SpatiallyIndexedSkeletonLayer) { - super( - base.chunkManager, - { - getSources: () => { - return [ - [ - { - chunkSource: base.source, - chunkToMultiscaleTransform: mat4.create(), - }, - ], - ]; - }, - } as any, - { - transform: base.displayState.transform, - localPosition: (base.displayState as any).localPosition, - }, - ); - // @ts-expect-error RenderHelper requires panel-specific initialization here. - this.renderHelper = this.registerDisposer(new RenderHelper(base, true)); - this.renderOptions = base.displayState.skeletonRenderingOptions.params2d; - this.layerChunkProgressInfo = base.layerChunkProgressInfo; - this.registerDisposer(base); - const { renderOptions } = this; - this.registerDisposer( - renderOptions.mode.changed.add(this.redrawNeeded.dispatch), - ); - this.registerDisposer( - renderOptions.lineWidth.changed.add(this.redrawNeeded.dispatch), - ); - this.registerDisposer(base.redrawNeeded.add(this.redrawNeeded.dispatch)); - this.initializeCounterpart(); - } - get gl() { - return this.base.gl; - } - - getValueAt(position: Float32Array) { - position; - return undefined; - } - - draw(_renderContext: SliceViewRenderContext) {} -} export class SliceViewPanelSpatiallyIndexedSkeletonLayer extends SliceViewPanelRenderLayer { private renderHelper: RenderHelper; private browseRenderHelper: RenderHelper; private renderOptions: ViewSpecificSkeletonRenderingOptions; private transformedSources: TransformedSource[][] = []; + backend: ChunkRenderLayerFrontend; constructor(public base: SpatiallyIndexedSkeletonLayer) { super(); + this.backend = base.backend; this.renderHelper = this.registerDisposer(new RenderHelper(base, true)); this.browseRenderHelper = this.registerDisposer( new RenderHelper(base.chunkGeometryRenderLayerInterface, true), @@ -3579,6 +3462,7 @@ export class SliceViewPanelSpatiallyIndexedSkeletonLayer extends SliceViewPanelR >, ) { super.attach(attachment); + const baseLayer = this.base; const redrawNeeded = this.redrawNeeded; attachment.registerDisposer( @@ -3602,7 +3486,17 @@ export class SliceViewPanelSpatiallyIndexedSkeletonLayer extends SliceViewPanelR context.registerDisposer(tsource.source); } } + attachment.view.flushBackendProjectionParameters(); this.transformedSources = transformedSources; + baseLayer.rpc!.invoke( + SPATIALLY_INDEXED_SKELETON_RENDER_LAYER_UPDATE_SOURCES_RPC_ID, + { + layer: baseLayer.backend.rpcId, + view: attachment.view.rpcId, + displayDimensionRenderInfo, + sources: serializeAllTransformedSources(transformedSources), + }, + ); redrawNeeded.dispatch(); return transformedSources; }, diff --git a/src/ui/spatial_skeleton_edit_tool.ts b/src/ui/spatial_skeleton_edit_tool.ts index 85717fd42..00443d811 100644 --- a/src/ui/spatial_skeleton_edit_tool.ts +++ b/src/ui/spatial_skeleton_edit_tool.ts @@ -41,7 +41,6 @@ import type { SpatiallyIndexedSkeletonLayer } from "#src/skeleton/frontend.js"; import { PerspectiveViewSpatiallyIndexedSkeletonLayer, SliceViewPanelSpatiallyIndexedSkeletonLayer, - SliceViewSpatiallyIndexedSkeletonLayer, } from "#src/skeleton/frontend.js"; import { StatusMessage } from "#src/status.js"; import type { SpatialSkeletonToolPointInfo } from "#src/ui/spatial_skeleton_tool_messages.js"; @@ -174,9 +173,6 @@ abstract class SpatialSkeletonToolBase extends LayerTool if (pickedLayer instanceof SliceViewPanelSpatiallyIndexedSkeletonLayer) { return pickedLayer.base; } - if (pickedLayer instanceof SliceViewSpatiallyIndexedSkeletonLayer) { - return pickedLayer.base; - } return this.layer.getSpatiallyIndexedSkeletonLayer(); }