@idetik/core 0.35.5 → 0.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -638,7 +638,7 @@ interface LayerProps {
638
638
  */
639
639
  declare abstract class Layer {
640
640
  abstract readonly type: string;
641
- private objects_;
641
+ private readonly coverageGroups_;
642
642
  private state_;
643
643
  private attached_;
644
644
  private readonly callbacks_;
@@ -653,14 +653,12 @@ declare abstract class Layer {
653
653
  onDetached(context: IdetikContext): void;
654
654
  protected attach(_context: IdetikContext): void;
655
655
  protected detach(_context: IdetikContext): void;
656
- get objects(): RenderableObject[];
656
+ get coverageGroups(): ReadonlyMap<number | null, readonly RenderableObject[]>;
657
657
  get state(): LayerState;
658
658
  addStateChangeCallback(callback: StateChangeCallback): void;
659
659
  removeStateChangeCallback(callback: StateChangeCallback): void;
660
- hasMultipleLODs(): boolean;
661
660
  protected setState(newState: LayerState): void;
662
- protected addObject(object: RenderableObject): void;
663
- protected removeObject(object: RenderableObject): void;
661
+ protected addObject(object: RenderableObject, coverageGroup?: number | null): void;
664
662
  protected clearObjects(): void;
665
663
  /**
666
664
  * Get uniforms for shader program. Override in derived classes that need custom uniforms.
@@ -675,7 +673,7 @@ declare abstract class Renderer {
675
673
  private height_;
676
674
  protected renderedObjects_: number;
677
675
  protected abstract resize(width: number, height: number): void;
678
- protected abstract renderObject(layer: Layer, objectIndex: number, camera: Camera): void;
676
+ protected abstract renderObject(layer: Layer, object: RenderableObject, camera: Camera): void;
679
677
  protected abstract clear(): void;
680
678
  constructor(canvas: HTMLCanvasElement);
681
679
  beginFrame(): void;
@@ -1527,6 +1525,7 @@ declare class ImageLayer extends Layer implements ChannelsEnabled {
1527
1525
  private orientation_;
1528
1526
  private readonly onPickValue_?;
1529
1527
  private readonly visibleChunks_;
1528
+ private orderedChunks_;
1530
1529
  private readonly pool_;
1531
1530
  private readonly initialChannelProps_?;
1532
1531
  private readonly channelChangeCallbacks_;
@@ -1551,7 +1550,7 @@ declare class ImageLayer extends Layer implements ChannelsEnabled {
1551
1550
  */
1552
1551
  setOrientation(orientation: SliceOrientation): void;
1553
1552
  private updateChunks;
1554
- hasMultipleLODs(): boolean;
1553
+ private rebuildRenderGroups;
1555
1554
  get lastPresentationTimeCoord(): number | undefined;
1556
1555
  private isPresentationStale;
1557
1556
  onEvent(event: EventContext): void;
@@ -1622,6 +1621,7 @@ declare class VolumeLayer extends Layer implements ChannelsEnabled {
1622
1621
  private updateVolumeTransform;
1623
1622
  private releaseAndRemoveVolume;
1624
1623
  update(viewport?: Viewport): void;
1624
+ private rebuildObjects;
1625
1625
  getUniforms(): Record<string, unknown>;
1626
1626
  }
1627
1627
 
@@ -1704,7 +1704,6 @@ declare class LabelLayer extends Layer {
1704
1704
  */
1705
1705
  setOrientation(orientation: SliceOrientation): void;
1706
1706
  private updateChunks;
1707
- hasMultipleLODs(): boolean;
1708
1707
  private isPresentationStale;
1709
1708
  onEvent(event: EventContext): void;
1710
1709
  private pickAtRay;
package/dist/index.js CHANGED
@@ -1600,6 +1600,9 @@ class eQ {
1600
1600
  currentViewport_ = null;
1601
1601
  currentScissor_ = null;
1602
1602
  currentCullingMode_ = null;
1603
+ stencilFunc_ = null;
1604
+ stencilRef_ = null;
1605
+ stencilFuncMask_ = null;
1603
1606
  constructor(A) {
1604
1607
  this.gl_ = A, this.gl_.frontFace(this.gl_.CW);
1605
1608
  }
@@ -1689,6 +1692,9 @@ class eQ {
1689
1692
  setStencilTest(A) {
1690
1693
  A ? this.enable(this.gl_.STENCIL_TEST) : this.disable(this.gl_.STENCIL_TEST);
1691
1694
  }
1695
+ setStencilFunc(A, I, B) {
1696
+ (this.stencilFunc_ !== A || this.stencilRef_ !== I || this.stencilFuncMask_ !== B) && (this.gl_.stencilFunc(A, I, B), this.stencilFunc_ = A, this.stencilRef_ = I, this.stencilFuncMask_ = B);
1697
+ }
1692
1698
  }
1693
1699
  const nQ = PB($(), [1, -1, 1]);
1694
1700
  class GQ extends RC {
@@ -1698,6 +1704,7 @@ class GQ extends RC {
1698
1704
  textures_;
1699
1705
  state_;
1700
1706
  renderedObjectsPerFrame_ = 0;
1707
+ stencilRef_ = 0;
1701
1708
  currentViewportSize_ = [0, 0];
1702
1709
  constructor(A) {
1703
1710
  super(A);
@@ -1720,7 +1727,7 @@ class GQ extends RC {
1720
1727
  return this.textures_.textureCount;
1721
1728
  }
1722
1729
  render(A) {
1723
- this.renderedObjects_ = 0, this.renderedObjectsPerFrame_ = 0;
1730
+ this.renderedObjects_ = 0, this.renderedObjectsPerFrame_ = 0, this.stencilRef_ = 0;
1724
1731
  const I = [], B = [];
1725
1732
  for (const D of A.layers)
1726
1733
  (D.blendMode === "none" ? I : B).push(D);
@@ -1755,33 +1762,38 @@ class GQ extends RC {
1755
1762
  this.renderedObjects_ = this.renderedObjectsPerFrame_;
1756
1763
  }
1757
1764
  initStencil() {
1758
- this.gl_.clearStencil(0), this.gl_.stencilMask(255), this.gl_.stencilFunc(this.gl_.EQUAL, 0, 255), this.gl_.stencilOp(this.gl_.KEEP, this.gl_.KEEP, this.gl_.INCR);
1765
+ this.gl_.clearStencil(0), this.gl_.stencilMask(255), this.gl_.stencilOp(this.gl_.KEEP, this.gl_.KEEP, this.gl_.REPLACE);
1766
+ }
1767
+ setCoverageStencil(A) {
1768
+ this.state_.setStencilTest(A !== null), A !== null && (this.stencilRef_ += 1, this.stencilRef_ > 255 && k.warn(
1769
+ "WebGLRenderer",
1770
+ "Exceeded 255 stencil coverage groups in one frame; dedup may be incorrect"
1771
+ ), this.state_.setStencilFunc(this.gl_.NOTEQUAL, this.stencilRef_, 255));
1759
1772
  }
1760
1773
  renderLayer(A, I, B) {
1761
- if (A.objects.length === 0) return;
1762
1774
  this.state_.setBlendingMode(A.blendMode);
1763
- const C = A.hasMultipleLODs();
1764
- this.state_.setStencilTest(C), C && this.gl_.clear(this.gl_.STENCIL_BUFFER_BIT), A.objects.forEach((Q, E) => {
1765
- B.intersectsWithBox3(Q.boundingBox) && (this.renderObject(A, E, I), this.renderedObjectsPerFrame_ += 1);
1766
- });
1775
+ for (const [C, Q] of A.coverageGroups) {
1776
+ this.setCoverageStencil(C);
1777
+ for (const E of Q)
1778
+ B.intersectsWithBox3(E.boundingBox) && (this.renderObject(A, E, I), this.renderedObjectsPerFrame_ += 1);
1779
+ }
1767
1780
  }
1768
1781
  renderObject(A, I, B) {
1769
- const C = A.objects[I];
1770
- if (C.popStaleTextures().forEach((E) => {
1771
- this.textures_.dispose(E);
1772
- }), !C.programName) return;
1773
- this.state_.setCullFaceMode(C.cullFaceMode), this.state_.setDepthTesting(C.depthTest), this.state_.setDepthMask(C.depthTest), this.bindings_.bindGeometry(C.geometry), C.textures.forEach((E, i) => {
1774
- this.textures_.bindTexture(E, i);
1782
+ if (I.popStaleTextures().forEach((Q) => {
1783
+ this.textures_.dispose(Q);
1784
+ }), !I.programName) return;
1785
+ this.state_.setCullFaceMode(I.cullFaceMode), this.state_.setDepthTesting(I.depthTest), this.bindings_.bindGeometry(I.geometry), I.textures.forEach((Q, E) => {
1786
+ this.textures_.bindTexture(Q, E);
1775
1787
  });
1776
- const Q = this.programs_.use(C.programName);
1777
- if (this.drawGeometry(C.geometry, C, A, Q, B), C.wireframeEnabled) {
1778
- this.bindings_.bindGeometry(C.wireframeGeometry);
1779
- const E = this.programs_.use("wireframe");
1780
- E.setUniform("u_color", C.wireframeColor.rgb), this.drawGeometry(
1781
- C.wireframeGeometry,
1782
- C,
1788
+ const C = this.programs_.use(I.programName);
1789
+ if (this.drawGeometry(I.geometry, I, A, C, B), I.wireframeEnabled) {
1790
+ this.bindings_.bindGeometry(I.wireframeGeometry);
1791
+ const Q = this.programs_.use("wireframe");
1792
+ Q.setUniform("u_color", I.wireframeColor.rgb), this.drawGeometry(
1793
+ I.wireframeGeometry,
1794
+ I,
1783
1795
  A,
1784
- E,
1796
+ Q,
1785
1797
  B
1786
1798
  );
1787
1799
  }
@@ -1869,7 +1881,9 @@ class GQ extends RC {
1869
1881
  this.state_.setViewport(B);
1870
1882
  }
1871
1883
  clear() {
1872
- this.gl_.clearColor(0, 0, 0, 0), this.gl_.clear(this.gl_.COLOR_BUFFER_BIT | this.gl_.DEPTH_BUFFER_BIT), this.state_.setDepthTesting(!0), this.gl_.depthFunc(this.gl_.LEQUAL);
1884
+ this.gl_.clearColor(0, 0, 0, 0), this.gl_.clear(
1885
+ this.gl_.COLOR_BUFFER_BIT | this.gl_.DEPTH_BUFFER_BIT | this.gl_.STENCIL_BUFFER_BIT
1886
+ ), this.state_.setDepthTesting(!0), this.gl_.depthFunc(this.gl_.LEQUAL);
1873
1887
  }
1874
1888
  }
1875
1889
  function ZA(g, A) {
@@ -11872,7 +11886,7 @@ class OA {
11872
11886
  }
11873
11887
  }
11874
11888
  class KI {
11875
- objects_ = [];
11889
+ coverageGroups_ = /* @__PURE__ */ new Map();
11876
11890
  state_ = "initialized";
11877
11891
  attached_ = !1;
11878
11892
  callbacks_ = [];
@@ -11906,8 +11920,8 @@ class KI {
11906
11920
  }
11907
11921
  detach(A) {
11908
11922
  }
11909
- get objects() {
11910
- return this.objects_;
11923
+ get coverageGroups() {
11924
+ return this.coverageGroups_;
11911
11925
  }
11912
11926
  get state() {
11913
11927
  return this.state_;
@@ -11921,22 +11935,16 @@ class KI {
11921
11935
  throw new Error(`Callback to remove could not be found: ${A}`);
11922
11936
  this.callbacks_.splice(I, 1);
11923
11937
  }
11924
- hasMultipleLODs() {
11925
- return !1;
11926
- }
11927
11938
  setState(A) {
11928
11939
  const I = this.state_;
11929
11940
  this.state_ = A, this.callbacks_.forEach((B) => B(A, I));
11930
11941
  }
11931
- addObject(A) {
11932
- this.objects_.push(A);
11933
- }
11934
- removeObject(A) {
11935
- const I = this.objects_.indexOf(A);
11936
- I !== -1 && this.objects_.splice(I, 1);
11942
+ addObject(A, I = null) {
11943
+ const B = this.coverageGroups_.get(I);
11944
+ B ? B.push(A) : this.coverageGroups_.set(I, [A]);
11937
11945
  }
11938
11946
  clearObjects() {
11939
- this.objects_ = [];
11947
+ this.coverageGroups_.clear();
11940
11948
  }
11941
11949
  /**
11942
11950
  * Get uniforms for shader program. Override in derived classes that need custom uniforms.
@@ -12453,6 +12461,7 @@ class eC extends KI {
12453
12461
  orientation_;
12454
12462
  onPickValue_;
12455
12463
  visibleChunks_ = /* @__PURE__ */ new Map();
12464
+ orderedChunks_ = [];
12456
12465
  pool_ = new pg();
12457
12466
  initialChannelProps_;
12458
12467
  channelChangeCallbacks_ = [];
@@ -12480,22 +12489,20 @@ class eC extends KI {
12480
12489
  onPickValue: E,
12481
12490
  ...i
12482
12491
  }) {
12483
- super(i), this.setState("initialized"), this.source_ = A, this.policy_ = B, this.sliceCoords_ = I, this.orientation_ = C ?? "XY", this.axes_ = MA(this.orientation_), this.planeRotation_ = dA(this.axes_), this.channelProps_ = Q, this.initialChannelProps_ = Q, this.onPickValue_ = E;
12492
+ super({ blendMode: "additive", ...i }), this.setState("initialized"), this.source_ = A, this.policy_ = B, this.sliceCoords_ = I, this.orientation_ = C ?? "XY", this.axes_ = MA(this.orientation_), this.planeRotation_ = dA(this.axes_), this.channelProps_ = Q, this.initialChannelProps_ = Q, this.onPickValue_ = E;
12484
12493
  }
12485
12494
  attach(A) {
12486
12495
  this.context_ = A, this.chunkStoreView_ = A.chunkManager.addView(
12487
12496
  this.source_,
12488
12497
  this.policy_,
12489
12498
  this.axes_
12499
+ ), hC(
12500
+ this.channelProps_,
12501
+ this.chunkStoreView_.channelCount
12490
12502
  );
12491
- const I = this.chunkStoreView_.channelCount;
12492
- if (hC(this.channelProps_, I), I > 1 && this.sliceCoords_.c !== void 0 && this.sliceCoords_.c.length > 1)
12493
- throw new Error(
12494
- `ImageLayer requires exactly one channel in sliceCoords.c for multi-channel sources (found ${I} channels). Use one layer per channel.`
12495
- );
12496
12503
  }
12497
12504
  detach(A) {
12498
- this.releaseAndRemoveChunks(this.visibleChunks_.keys()), this.clearObjects(), this.chunkStoreView_?.dispose(), this.chunkStoreView_ = void 0, this.context_ = void 0;
12505
+ this.releaseAndRemoveChunks(this.visibleChunks_.keys()), this.orderedChunks_ = [], this.clearObjects(), this.chunkStoreView_?.dispose(), this.chunkStoreView_ = void 0, this.context_ = void 0;
12499
12506
  }
12500
12507
  update(A) {
12501
12508
  if (!A || !this.chunkStoreView_) return;
@@ -12515,7 +12522,7 @@ class eC extends KI {
12515
12522
  * for the new plane, chunks already resident in the shared cache are reused.
12516
12523
  */
12517
12524
  setOrientation(A) {
12518
- A !== this.orientation_ && (this.releaseAndRemoveChunks(this.visibleChunks_.keys()), this.clearObjects(), this.chunkStoreView_?.dispose(), this.lastPresentationTimeStamp_ = void 0, this.lastPresentationTimeCoord_ = void 0, this.orientation_ = A, this.axes_ = MA(A), this.planeRotation_ = dA(this.axes_), this.context_ && (this.chunkStoreView_ = this.context_.chunkManager.addView(
12525
+ A !== this.orientation_ && (this.releaseAndRemoveChunks(this.visibleChunks_.keys()), this.orderedChunks_ = [], this.clearObjects(), this.chunkStoreView_?.dispose(), this.lastPresentationTimeStamp_ = void 0, this.lastPresentationTimeCoord_ = void 0, this.orientation_ = A, this.axes_ = MA(A), this.planeRotation_ = dA(this.axes_), this.context_ && (this.chunkStoreView_ = this.context_.chunkManager.addView(
12519
12526
  this.source_,
12520
12527
  this.policy_,
12521
12528
  this.axes_
@@ -12533,14 +12540,20 @@ class eC extends KI {
12533
12540
  const I = this.chunkStoreView_.getChunksToRender(), B = new Set(I), C = Array.from(this.visibleChunks_.keys()).filter(
12534
12541
  (Q) => !B.has(Q)
12535
12542
  );
12536
- this.releaseAndRemoveChunks(C), this.clearObjects();
12537
- for (const Q of I) {
12538
- const E = this.getImageForChunk(Q, Q.texture);
12539
- this.visibleChunks_.set(Q, E), this.addObject(E);
12540
- }
12543
+ this.releaseAndRemoveChunks(C);
12544
+ for (const Q of I)
12545
+ this.visibleChunks_.set(
12546
+ Q,
12547
+ this.getImageForChunk(Q, Q.texture)
12548
+ );
12549
+ this.orderedChunks_ = I, this.rebuildRenderGroups();
12541
12550
  }
12542
- hasMultipleLODs() {
12543
- return this.chunkStoreView_ ? this.chunkStoreView_.lodCount > 1 : !1;
12551
+ rebuildRenderGroups() {
12552
+ this.clearObjects();
12553
+ for (const A of this.orderedChunks_) {
12554
+ const I = this.visibleChunks_.get(A), B = A.chunkIndex.c;
12555
+ I === void 0 || this.channelProps_?.[B]?.visible === !1 || this.addObject(I, B);
12556
+ }
12544
12557
  }
12545
12558
  get lastPresentationTimeCoord() {
12546
12559
  return this.lastPresentationTimeCoord_;
@@ -12658,7 +12671,7 @@ class eC extends KI {
12658
12671
  setChannelProps(A) {
12659
12672
  this.channelProps_ = A, this.visibleChunks_.forEach((I, B) => {
12660
12673
  I.setChannelProps(this.getChannelPropsForChunk(B));
12661
- }), this.channelChangeCallbacks_.forEach((I) => {
12674
+ }), this.rebuildRenderGroups(), this.channelChangeCallbacks_.forEach((I) => {
12662
12675
  I();
12663
12676
  });
12664
12677
  }
@@ -12950,7 +12963,7 @@ class Fo extends KI {
12950
12963
  detach(A) {
12951
12964
  for (const I of this.currentVolumes_.values())
12952
12965
  this.releaseAndRemoveVolume(I);
12953
- this.clearObjects(), this.chunkStoreView_?.dispose(), this.chunkStoreView_ = void 0;
12966
+ this.currentVolumes_.clear(), this.clearObjects(), this.chunkStoreView_?.dispose(), this.chunkStoreView_ = void 0;
12954
12967
  }
12955
12968
  updateChunks() {
12956
12969
  if (!this.chunkStoreView_) return;
@@ -12959,10 +12972,9 @@ class Fo extends KI {
12959
12972
  if (this.lastLoadedTime_ !== I || B.size !== this.currentVolumes_.size || this.lastNumRenderedChannelChunks_ !== A.length) {
12960
12973
  for (const [Q, E] of this.currentVolumes_)
12961
12974
  B.has(Q) || (this.releaseAndRemoveVolume(E), this.currentVolumes_.delete(Q));
12962
- this.clearObjects();
12963
12975
  for (const [Q, E] of B) {
12964
12976
  const i = this.getOrCreateVolume(Q, E);
12965
- i.wireframeEnabled = this.debugShowWireframes, this.currentVolumes_.set(Q, i), this.addObject(i);
12977
+ i.wireframeEnabled = this.debugShowWireframes, this.currentVolumes_.set(Q, i);
12966
12978
  }
12967
12979
  this.lastLoadedTime_ = I, this.lastNumRenderedChannelChunks_ = A.length;
12968
12980
  }
@@ -12995,7 +13007,13 @@ class Fo extends KI {
12995
13007
  A.camera.getViewProjection()
12996
13008
  );
12997
13009
  const I = A.cameraControls?.isMoving ?? !1;
12998
- this.interactiveStepSizeScale_ = I ? xi : 1, this.updateChunks(), Ti(this.objects, A.camera);
13010
+ this.interactiveStepSizeScale_ = I ? xi : 1, this.updateChunks(), this.rebuildObjects(A.camera);
13011
+ }
13012
+ rebuildObjects(A) {
13013
+ const I = Array.from(this.currentVolumes_.values());
13014
+ Ti(I, A), this.clearObjects();
13015
+ for (const B of I)
13016
+ this.addObject(B);
12999
13017
  }
13000
13018
  getUniforms() {
13001
13019
  return {
@@ -13215,12 +13233,9 @@ class GC extends KI {
13215
13233
  this.releaseAndRemoveChunks(C), this.clearObjects();
13216
13234
  for (const Q of I) {
13217
13235
  const E = this.getLabelForChunk(Q, Q.texture);
13218
- this.visibleChunks_.set(Q, E), this.addObject(E);
13236
+ this.visibleChunks_.set(Q, E), this.addObject(E, 0);
13219
13237
  }
13220
13238
  }
13221
- hasMultipleLODs() {
13222
- return this.chunkStoreView_ ? this.chunkStoreView_.lodCount > 1 : !1;
13223
- }
13224
13239
  isPresentationStale() {
13225
13240
  return this.lastPresentationTimeStamp_ === void 0 ? !1 : performance.now() - this.lastPresentationTimeStamp_ > GC.STALE_PRESENTATION_MS_;
13226
13241
  }