@kitware/vtk.js 30.3.3 → 30.4.1

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.
@@ -9,6 +9,7 @@ export interface IRenderWindowInitialValues {
9
9
  interactor?: any,
10
10
  neverRendered?: boolean,
11
11
  numberOfLayers?: number
12
+ childRenderWindows?: vtkRenderWindow[],
12
13
  }
13
14
 
14
15
  interface IStatistics {
@@ -42,6 +43,12 @@ export interface vtkRenderWindow extends vtkObject {
42
43
  */
43
44
  addRenderer(renderer: vtkRenderer): void;
44
45
 
46
+ /**
47
+ * Add a child render window
48
+ * @param {vtkRenderWindow} renderWindow The vtkRenderWindow instance.
49
+ */
50
+ addRenderWindow(renderWindow: vtkRenderWindow): void;
51
+
45
52
  /**
46
53
  * Add renderer
47
54
  * @param view
@@ -87,6 +94,16 @@ export interface vtkRenderWindow extends vtkObject {
87
94
  */
88
95
  getRenderersByReference(): vtkRenderer[];
89
96
 
97
+ /**
98
+ *
99
+ */
100
+ getChildRenderWindows(): vtkRenderWindow[];
101
+
102
+ /**
103
+ *
104
+ */
105
+ getChildRenderWindowsByReference(): vtkRenderWindow[];
106
+
90
107
  /**
91
108
  *
92
109
  */
@@ -136,6 +136,14 @@ function vtkRenderWindow(publicAPI, model) {
136
136
  macro.setImmediate(publicAPI.render);
137
137
  return model._views.map(view => view.captureNextImage ? view.captureNextImage(format, opts) : undefined).filter(i => !!i);
138
138
  };
139
+ publicAPI.addRenderWindow = child => {
140
+ if (model.childRenderWindows.includes(child)) {
141
+ return false;
142
+ }
143
+ model.childRenderWindows.push(child);
144
+ publicAPI.modified();
145
+ return true;
146
+ };
139
147
  }
140
148
 
141
149
  // ----------------------------------------------------------------------------
@@ -148,7 +156,8 @@ const DEFAULT_VALUES = {
148
156
  views: [],
149
157
  interactor: null,
150
158
  neverRendered: true,
151
- numberOfLayers: 1
159
+ numberOfLayers: 1,
160
+ childRenderWindows: []
152
161
  };
153
162
 
154
163
  // ----------------------------------------------------------------------------
@@ -161,7 +170,7 @@ function extend(publicAPI, model) {
161
170
  macro.obj(publicAPI, model);
162
171
  macro.setGet(publicAPI, model, ['interactor', 'numberOfLayers', '_views', 'defaultViewAPI']);
163
172
  macro.get(publicAPI, model, ['neverRendered']);
164
- macro.getArray(publicAPI, model, ['renderers']);
173
+ macro.getArray(publicAPI, model, ['renderers', 'childRenderWindows']);
165
174
  macro.moveToProtected(publicAPI, model, ['views']);
166
175
  macro.event(publicAPI, model, 'completion');
167
176
 
@@ -28,11 +28,11 @@ function vtkForwardPass(publicAPI, model) {
28
28
  const numlayers = viewNode.getRenderable().getNumberOfLayers();
29
29
 
30
30
  // iterate over renderers
31
- const renderers = viewNode.getChildren();
31
+ const renderers = viewNode.getRenderable().getRenderersByReference();
32
32
  for (let i = 0; i < numlayers; i++) {
33
33
  for (let index = 0; index < renderers.length; index++) {
34
- const renNode = renderers[index];
35
- const ren = viewNode.getRenderable().getRenderers()[index];
34
+ const ren = renderers[index];
35
+ const renNode = viewNode.getViewNodeFor(ren);
36
36
  if (ren.getDraw() && ren.getLayer() === i) {
37
37
  // check for both opaque and volume actors
38
38
  model.opaqueActorCount = 0;
@@ -923,8 +923,8 @@ function vtkOpenGLImageMapper(publicAPI, model) {
923
923
  // Assuming labelOutlineThicknessArray contains the thickness for each segment
924
924
  for (let i = 0; i < lWidth; ++i) {
925
925
  // Retrieve the thickness value for the current segment index.
926
- // If the value is undefined, null, or 0, use the first element's value as a default.
927
- const thickness = labelOutlineThicknessArray[i] || labelOutlineThicknessArray[0];
926
+ // If the value is undefined, use the first element's value as a default, otherwise use the value (even if 0)
927
+ const thickness = typeof labelOutlineThicknessArray[i] !== 'undefined' ? labelOutlineThicknessArray[i] : labelOutlineThicknessArray[0];
928
928
  lTable[i] = thickness;
929
929
  }
930
930
  model.labelOutlineThicknessTexture.releaseGraphicsResources(model._openGLRenderWindow);
@@ -18,6 +18,7 @@ export interface IOpenGLRenderWindowInitialValues {
18
18
  shaderCache?: null;
19
19
  initialized?: boolean;
20
20
  context?: WebGLRenderingContext | WebGL2RenderingContext;
21
+ context2D?: CanvasRenderingContext2D;
21
22
  canvas?: HTMLCanvasElement;
22
23
  cursorVisibility?: boolean;
23
24
  cursor?: string;
@@ -40,13 +41,6 @@ export interface ICaptureOptions {
40
41
  scale?: number
41
42
  }
42
43
 
43
- export interface I3DContextOptions {
44
- preserveDrawingBuffer?: boolean;
45
- depth?: boolean;
46
- alpha?: boolean;
47
- powerPreference?: string;
48
- }
49
-
50
44
  type vtkOpenGLRenderWindowBase = vtkObject & Omit<vtkAlgorithm,
51
45
  | 'getInputData'
52
46
  | 'setInputData'
@@ -228,9 +222,44 @@ export interface vtkOpenGLRenderWindow extends vtkOpenGLRenderWindowBase {
228
222
 
229
223
  /**
230
224
  *
231
- * @param {I3DContextOptions} options
225
+ * @param {WebGLContextAttributes} options
226
+ */
227
+ get3DContext(options: WebGLContextAttributes): Nullable<WebGLRenderingContext>;
228
+
229
+ /**
230
+ *
231
+ * @param {CanvasRenderingContext2DSettings} options
232
+ */
233
+ get2DContext(options: CanvasRenderingContext2DSettings): Nullable<CanvasRenderingContext2D>;
234
+
235
+ /**
236
+ * Copy the content of the root parent, if there is one, to the canvas
237
+ */
238
+ copyParentContent(): void;
239
+
240
+ /**
241
+ * Resize this render window using the size of its children
242
+ * The new size of the renderwindow is the size of the bounding box
243
+ * containing all the child render windows
244
+ */
245
+ resizeFromChildRenderWindows(): void;
246
+
247
+ /**
248
+ * Returns the last ancestor of type vtkOpenGLRenderWindow if there is one
249
+ * If there is no parent vtkOpenGLRenderWindow, returns undefined
250
+ */
251
+ getRootOpenGLRenderWindow(): vtkOpenGLRenderWindow | undefined;
252
+
253
+ /**
254
+ * The context 2D is created during initialization instead of the WebGL context
255
+ * when there is a parent render window
256
+ */
257
+ getContext2D(): CanvasRenderingContext2D | undefined;
258
+
259
+ /**
260
+ *
232
261
  */
233
- get3DContext(options: I3DContextOptions): Nullable<WebGLRenderingContext>;
262
+ setContext2D(context2D: CanvasRenderingContext2D | undefined): boolean;
234
263
 
235
264
  /**
236
265
  *
@@ -5,7 +5,7 @@ import vtkForwardPass from './ForwardPass.js';
5
5
  import vtkHardwareSelector from './HardwareSelector.js';
6
6
  import vtkShaderCache from './ShaderCache.js';
7
7
  import vtkTextureUnitManager from './TextureUnitManager.js';
8
- import vtkViewNodeFactory from './ViewNodeFactory.js';
8
+ import vtkViewNodeFactory, { registerOverride } from './ViewNodeFactory.js';
9
9
  import vtkRenderPass from '../SceneGraph/RenderPass.js';
10
10
  import vtkRenderWindowViewNode from '../SceneGraph/RenderWindowViewNode.js';
11
11
  import { createContextProxyHandler } from './RenderWindow/ContextProxy.js';
@@ -21,6 +21,7 @@ const SCREENSHOT_PLACEHOLDER = {
21
21
  width: '100%',
22
22
  height: '100%'
23
23
  };
24
+ const parentMethodsToProxy = ['activateTexture', 'deactivateTexture', 'disableCullFace', 'enableCullFace', 'get3DContext', 'getActiveFramebuffer', 'getContext', 'getDefaultTextureByteSize', 'getDefaultTextureInternalFormat', 'getDefaultToWebgl2', 'getGLInformations', 'getGraphicsMemoryInfo', 'getGraphicsResourceForObject', 'getHardwareMaximumLineWidth', 'getPixelData', 'getShaderCache', 'getTextureUnitForTexture', 'getTextureUnitManager', 'getWebgl2', 'makeCurrent', 'releaseGraphicsResources', 'releaseGraphicsResourcesForObject', 'restoreContext', 'setActiveFramebuffer', 'setContext', 'setDefaultToWebgl2', 'setGraphicsResourceForObject'];
24
25
  function checkRenderTargetSupport(gl, format, type) {
25
26
  // create temporary frame buffer and texture
26
27
  const framebuffer = gl.createFramebuffer();
@@ -70,7 +71,15 @@ function _preventDefault(e) {
70
71
  function vtkOpenGLRenderWindow(publicAPI, model) {
71
72
  // Set our className
72
73
  model.classHierarchy.push('vtkOpenGLRenderWindow');
73
- const cachingContextHandler = createContextProxyHandler();
74
+
75
+ // Only create a cachingContextHandler if needed
76
+ let cachingContextHandler;
77
+ function getCachingContextHandler() {
78
+ if (!cachingContextHandler) {
79
+ cachingContextHandler = createContextProxyHandler();
80
+ }
81
+ return cachingContextHandler;
82
+ }
74
83
  publicAPI.getViewNodeFactory = () => model.myFactory;
75
84
 
76
85
  // prevent default context lost handler
@@ -117,24 +126,40 @@ function vtkOpenGLRenderWindow(publicAPI, model) {
117
126
  }
118
127
  publicAPI.prepareNodes();
119
128
  publicAPI.addMissingNodes(model.renderable.getRenderersByReference());
129
+ publicAPI.addMissingNodes(model.renderable.getChildRenderWindowsByReference());
120
130
  publicAPI.removeUnusedNodes();
121
131
  publicAPI.initialize();
122
132
  model.children.forEach(child => {
123
- child.setOpenGLRenderWindow(publicAPI);
133
+ // Children can be openGl renderer or openGl render windows
134
+ // Only openGl renderers have a method setOpenGLRenderWindow
135
+ child.setOpenGLRenderWindow?.(publicAPI);
124
136
  });
125
137
  }
126
138
  };
127
139
  publicAPI.initialize = () => {
128
140
  if (!model.initialized) {
129
- model.context = publicAPI.get3DContext();
130
- model.textureUnitManager = vtkTextureUnitManager.newInstance();
131
- model.textureUnitManager.setContext(model.context);
132
- model.shaderCache.setContext(model.context);
133
- // initialize blending for transparency
134
- const gl = model.context;
135
- gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
136
- gl.depthFunc(gl.LEQUAL);
137
- gl.enable(gl.BLEND);
141
+ // Set root parent if there is one
142
+ // Some methods of the root parent are proxied (see parentMethodsToProxy)
143
+ model.rootOpenGLRenderWindow = publicAPI.getLastAncestorOfType('vtkOpenGLRenderWindow');
144
+ if (model.rootOpenGLRenderWindow) {
145
+ // Initialize a 2D context that will copy the content of the root parent
146
+ model.context2D = publicAPI.get2DContext();
147
+ } else {
148
+ // Initialize a 3D context that may be used by child render windows
149
+ model.context = publicAPI.get3DContext();
150
+ publicAPI.resizeFromChildRenderWindows();
151
+ if (model.context) {
152
+ createGLContext();
153
+ }
154
+ model.textureUnitManager = vtkTextureUnitManager.newInstance();
155
+ model.textureUnitManager.setContext(model.context);
156
+ model.shaderCache.setContext(model.context);
157
+ // initialize blending for transparency
158
+ const gl = model.context;
159
+ gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
160
+ gl.depthFunc(gl.LEQUAL);
161
+ gl.enable(gl.BLEND);
162
+ }
138
163
  model.initialized = true;
139
164
  }
140
165
  };
@@ -213,7 +238,11 @@ function vtkOpenGLRenderWindow(publicAPI, model) {
213
238
  vtkDebugMacro('using webgl1');
214
239
  result = model.canvas.getContext('webgl', options) || model.canvas.getContext('experimental-webgl', options);
215
240
  }
216
- return new Proxy(result, cachingContextHandler);
241
+ return new Proxy(result, getCachingContextHandler());
242
+ };
243
+ publicAPI.get2DContext = function () {
244
+ let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
245
+ return model.canvas.getContext('2d', options);
217
246
  };
218
247
  publicAPI.restoreContext = () => {
219
248
  const rp = vtkRenderPass.newInstance();
@@ -545,6 +574,37 @@ function vtkOpenGLRenderWindow(publicAPI, model) {
545
574
  if (model.notifyStartCaptureImage) {
546
575
  getCanvasDataURL();
547
576
  }
577
+ publicAPI.copyParentContent();
578
+ const childrenRW = model.renderable.getChildRenderWindowsByReference();
579
+ for (let i = 0; i < childrenRW.length; ++i) {
580
+ publicAPI.getViewNodeFor(childrenRW[i])?.traverseAllPasses();
581
+ }
582
+ };
583
+ publicAPI.copyParentContent = () => {
584
+ const rootParent = model.rootOpenGLRenderWindow;
585
+ if (!rootParent || !model.context2D) {
586
+ return;
587
+ }
588
+ const parentCanvas = rootParent.getCanvas();
589
+ const selfCanvas = model.canvas;
590
+ model.context2D.drawImage(parentCanvas, 0, parentCanvas.height - selfCanvas.height,
591
+ // source y axis is inverted
592
+ selfCanvas.width, selfCanvas.height, 0, 0, selfCanvas.width, selfCanvas.height);
593
+ };
594
+ publicAPI.resizeFromChildRenderWindows = () => {
595
+ // Adapt the size of the parent render window to the child render windows
596
+ const childrenRW = model.renderable.getChildRenderWindowsByReference();
597
+ if (childrenRW.length > 0) {
598
+ const maxSize = [0, 0];
599
+ for (let i = 0; i < childrenRW.length; ++i) {
600
+ const childSize = publicAPI.getViewNodeFor(childrenRW[i])?.getSize();
601
+ if (childSize) {
602
+ maxSize[0] = childSize[0] > maxSize[0] ? childSize[0] : maxSize[0];
603
+ maxSize[1] = childSize[1] > maxSize[1] ? childSize[1] : maxSize[1];
604
+ }
605
+ }
606
+ publicAPI.setSize(...maxSize);
607
+ }
548
608
  };
549
609
  publicAPI.disableCullFace = () => {
550
610
  if (model.cullFaceEnabled) {
@@ -593,7 +653,11 @@ function vtkOpenGLRenderWindow(publicAPI, model) {
593
653
  model.canvas.removeEventListener('webglcontextlost', _preventDefault);
594
654
  model.canvas.removeEventListener('webglcontextrestored', publicAPI.restoreContext);
595
655
  }
596
- publicAPI.delete = macro.chain(clearEvents, publicAPI.delete, publicAPI.setViewStream, deleteGLContext);
656
+ publicAPI.delete = macro.chain(() => {
657
+ if (model.context) {
658
+ deleteGLContext();
659
+ }
660
+ }, clearEvents, publicAPI.delete, publicAPI.setViewStream);
597
661
 
598
662
  // Do not trigger modified for performance reasons
599
663
  publicAPI.setActiveFramebuffer = newActiveFramebuffer => {
@@ -662,6 +726,20 @@ function vtkOpenGLRenderWindow(publicAPI, model) {
662
726
  glRen?.releaseGraphicsResources();
663
727
  });
664
728
  };
729
+
730
+ // Proxy some methods if needed
731
+ const publicAPIBeforeProxy = {
732
+ ...publicAPI
733
+ };
734
+ parentMethodsToProxy.forEach(methodName => {
735
+ publicAPI[methodName] = function () {
736
+ if (model.rootOpenGLRenderWindow) {
737
+ // Proxy only methods when the render window has a parent
738
+ return model.rootOpenGLRenderWindow[methodName](...arguments);
739
+ }
740
+ return publicAPIBeforeProxy[methodName](...arguments);
741
+ };
742
+ });
665
743
  }
666
744
 
667
745
  // ----------------------------------------------------------------------------
@@ -673,6 +751,7 @@ const DEFAULT_VALUES = {
673
751
  shaderCache: null,
674
752
  initialized: false,
675
753
  context: null,
754
+ context2D: null,
676
755
  canvas: null,
677
756
  cursorVisibility: true,
678
757
  cursor: 'pointer',
@@ -700,9 +779,10 @@ function extend(publicAPI, model) {
700
779
  vtkRenderWindowViewNode.extend(publicAPI, model, initialValues);
701
780
 
702
781
  // Create internal instances
703
- model.canvas = document.createElement('canvas');
704
- model.canvas.style.width = '100%';
705
- createGLContext();
782
+ if (!model.canvas) {
783
+ model.canvas = document.createElement('canvas');
784
+ model.canvas.style.width = '100%';
785
+ }
706
786
  if (!model.selector) {
707
787
  model.selector = vtkHardwareSelector.newInstance();
708
788
  model.selector.setOpenGLRenderWindow(publicAPI);
@@ -721,21 +801,17 @@ function extend(publicAPI, model) {
721
801
  model._graphicsResourceHash = new Map();
722
802
  model._glInformation = null;
723
803
  model.myFactory = vtkViewNodeFactory.newInstance();
724
- /* eslint-disable no-use-before-define */
725
- model.myFactory.registerOverride('vtkRenderWindow', newInstance);
726
- /* eslint-enable no-use-before-define */
727
-
728
804
  model.shaderCache = vtkShaderCache.newInstance();
729
805
  model.shaderCache.setOpenGLRenderWindow(publicAPI);
730
806
 
731
807
  // setup default forward pass rendering
732
808
  model.renderPasses[0] = vtkForwardPass.newInstance();
733
- macro.event(publicAPI, model, 'imageReady');
734
809
 
735
810
  // Build VTK API
736
- macro.get(publicAPI, model, ['shaderCache', 'textureUnitManager', 'webgl2', 'useBackgroundImage', 'activeFramebuffer']);
737
- macro.setGet(publicAPI, model, ['initialized', 'context', 'canvas', 'renderPasses', 'notifyStartCaptureImage', 'defaultToWebgl2', 'cursor', 'useOffScreen']);
811
+ macro.get(publicAPI, model, ['shaderCache', 'textureUnitManager', 'webgl2', 'useBackgroundImage', 'activeFramebuffer', 'rootOpenGLRenderWindow']);
812
+ macro.setGet(publicAPI, model, ['initialized', 'context', 'context2D', 'canvas', 'renderPasses', 'notifyStartCaptureImage', 'defaultToWebgl2', 'cursor', 'useOffScreen']);
738
813
  macro.setGetArray(publicAPI, model, ['size'], 2);
814
+ macro.event(publicAPI, model, 'imageReady');
739
815
  macro.event(publicAPI, model, 'windowResizeEvent');
740
816
 
741
817
  // Object methods
@@ -761,4 +837,7 @@ var vtkRenderWindow = {
761
837
  popMonitorGLContextCount
762
838
  };
763
839
 
840
+ // Register ourself to OpenGL backend if imported
841
+ registerOverride('vtkRenderWindow', newInstance);
842
+
764
843
  export { vtkRenderWindow as default, extend, newInstance, popMonitorGLContextCount, pushMonitorGLContextCount };
@@ -124,13 +124,13 @@ function vtkOpenGLRenderer(publicAPI, model) {
124
124
  if (!model.renderable.getTransparent()) {
125
125
  const background = model.renderable.getBackgroundByReference();
126
126
  // renderable ensures that background has 4 entries.
127
- model.context.clearColor(background[0], background[1], background[2], background[3]);
127
+ gl.clearColor(background[0], background[1], background[2], background[3]);
128
128
  clearMask |= gl.COLOR_BUFFER_BIT;
129
129
  }
130
130
  if (!model.renderable.getPreserveDepthBuffer()) {
131
131
  gl.clearDepth(1.0);
132
132
  clearMask |= gl.DEPTH_BUFFER_BIT;
133
- model.context.depthMask(true);
133
+ gl.depthMask(true);
134
134
  }
135
135
  gl.colorMask(true, true, true, true);
136
136
  const ts = publicAPI.getTiledSizeAndOrigin();
@@ -1119,7 +1119,7 @@ function vtkOpenGLVolumeMapper(publicAPI, model) {
1119
1119
  const tex = model._openGLRenderWindow.getGraphicsResourceForObject(scalars);
1120
1120
  // rebuild the scalarTexture if the data has changed
1121
1121
  toString = `${image.getMTime()}A${scalars.getMTime()}`;
1122
- const reBuildTex = !tex?.vtkObj || tex?.hash !== toString || model.scalarTextureString !== toString;
1122
+ const reBuildTex = !tex?.vtkObj || tex?.hash !== toString;
1123
1123
  if (reBuildTex) {
1124
1124
  // Build the textures
1125
1125
  const dims = image.getDimensions();
@@ -1128,13 +1128,11 @@ function vtkOpenGLVolumeMapper(publicAPI, model) {
1128
1128
  model.scalarTexture.releaseGraphicsResources(model._openGLRenderWindow);
1129
1129
  model.scalarTexture.resetFormatAndType();
1130
1130
  model.scalarTexture.create3DFilterableFromDataArray(dims[0], dims[1], dims[2], scalars, model.renderable.getPreferSizeOverAccuracy());
1131
- model.scalarTextureString = toString;
1132
1131
  if (scalars) {
1133
- model._openGLRenderWindow.setGraphicsResourceForObject(scalars, model.scalarTexture, model.scalarTextureString);
1132
+ model._openGLRenderWindow.setGraphicsResourceForObject(scalars, model.scalarTexture, toString);
1134
1133
  }
1135
1134
  } else {
1136
1135
  model.scalarTexture = tex.vtkObj;
1137
- model.scalarTextureString = tex.hash;
1138
1136
  }
1139
1137
  if (!model.tris.getCABO().getElementCount()) {
1140
1138
  // build the CABO
@@ -1214,8 +1212,8 @@ function vtkOpenGLVolumeMapper(publicAPI, model) {
1214
1212
  // Assuming labelOutlineThicknessArray contains the thickness for each segment
1215
1213
  for (let i = 0; i < lWidth; ++i) {
1216
1214
  // Retrieve the thickness value for the current segment index.
1217
- // If the value is undefined, null, or 0, use the first element's value as a default.
1218
- const thickness = labelOutlineThicknessArray[i] || labelOutlineThicknessArray[0];
1215
+ // If the value is undefined, use the first element's value as a default, otherwise use the value (even if 0)
1216
+ const thickness = typeof labelOutlineThicknessArray[i] !== 'undefined' ? labelOutlineThicknessArray[i] : labelOutlineThicknessArray[0];
1219
1217
  lTable[i] = thickness;
1220
1218
  }
1221
1219
  model.labelOutlineThicknessTexture.releaseGraphicsResources(model._openGLRenderWindow);
@@ -20,10 +20,12 @@ export interface IViewNodeInitialValues {
20
20
  export interface vtkViewNode extends vtkObject {
21
21
 
22
22
  /**
23
- *
23
+ * Add a child view node to this node, created from the renderable given as argument
24
+ * If the node creation fails or the argument is falsy, returns undefined
25
+ * Otherwise, returns the newly created node or the existing node
24
26
  * @param dobj
25
27
  */
26
- addMissingNode(dobj: any): void;
28
+ addMissingNode(dobj: any): vtkViewNode | undefined;
27
29
 
28
30
  /**
29
31
  *
@@ -66,6 +68,12 @@ export interface vtkViewNode extends vtkObject {
66
68
  */
67
69
  getFirstAncestorOfType(type: any): void;
68
70
 
71
+ /**
72
+ * Find the last parent/grandparent of the desired type
73
+ * @param type
74
+ */
75
+ getLastAncestorOfType(type: any): void;
76
+
69
77
  /**
70
78
  *
71
79
  */
@@ -63,27 +63,44 @@ function vtkViewNode(publicAPI, model) {
63
63
  }
64
64
  return model._parent.getFirstAncestorOfType(type);
65
65
  };
66
+ publicAPI.getLastAncestorOfType = type => {
67
+ if (!model._parent) {
68
+ return null;
69
+ }
70
+ const lastAncestor = model._parent.getLastAncestorOfType(type);
71
+ if (lastAncestor) {
72
+ return lastAncestor;
73
+ }
74
+ if (model._parent.isA(type)) {
75
+ return model._parent;
76
+ }
77
+ return null;
78
+ };
66
79
 
67
80
  // add a missing node/child for the passed in renderables. This should
68
81
  // be called only in between prepareNodes and removeUnusedNodes
69
82
  publicAPI.addMissingNode = dobj => {
70
83
  if (!dobj) {
71
- return;
84
+ return undefined;
72
85
  }
73
- const result = model._renderableChildMap.get(dobj);
86
+
74
87
  // if found just mark as visited
88
+ const result = model._renderableChildMap.get(dobj);
75
89
  if (result !== undefined) {
76
90
  result.setVisited(true);
77
- } else {
78
- // otherwise create a node
79
- const newNode = publicAPI.createViewNode(dobj);
80
- if (newNode) {
81
- newNode.setParent(publicAPI);
82
- newNode.setVisited(true);
83
- model._renderableChildMap.set(dobj, newNode);
84
- model.children.push(newNode);
85
- }
91
+ return result;
92
+ }
93
+
94
+ // otherwise create a node
95
+ const newNode = publicAPI.createViewNode(dobj);
96
+ if (newNode) {
97
+ newNode.setParent(publicAPI);
98
+ newNode.setVisited(true);
99
+ model._renderableChildMap.set(dobj, newNode);
100
+ model.children.push(newNode);
101
+ return newNode;
86
102
  }
103
+ return undefined;
87
104
  };
88
105
 
89
106
  // add missing nodes/children for the passed in renderables. This should
@@ -94,20 +111,7 @@ function vtkViewNode(publicAPI, model) {
94
111
  }
95
112
  for (let index = 0; index < dataObjs.length; ++index) {
96
113
  const dobj = dataObjs[index];
97
- const result = model._renderableChildMap.get(dobj);
98
- // if found just mark as visited
99
- if (result !== undefined) {
100
- result.setVisited(true);
101
- } else {
102
- // otherwise create a node
103
- const newNode = publicAPI.createViewNode(dobj);
104
- if (newNode) {
105
- newNode.setParent(publicAPI);
106
- newNode.setVisited(true);
107
- model._renderableChildMap.set(dobj, newNode);
108
- model.children.push(newNode);
109
- }
110
- }
114
+ publicAPI.addMissingNode(dobj);
111
115
  }
112
116
  };
113
117
 
@@ -125,6 +129,10 @@ function vtkViewNode(publicAPI, model) {
125
129
  if (cindex === -1) {
126
130
  child.setParent(publicAPI);
127
131
  model.children.push(child);
132
+ const childRenderable = child.getRenderable();
133
+ if (childRenderable) {
134
+ model._renderableChildMap.set(childRenderable, child);
135
+ }
128
136
  }
129
137
  child.setVisited(true);
130
138
  }
@@ -12,14 +12,6 @@ export interface vtkViewNodeFactory extends vtkObject {
12
12
  * @param dataObject
13
13
  */
14
14
  createNode(dataObject: any): void;
15
-
16
- /**
17
- * Give a function pointer to a class that will manufacture a vtkViewNode
18
- * when given a class name string.
19
- * @param className
20
- * @param func
21
- */
22
- registerOverride(className: any, func: any): void;
23
15
  }
24
16
 
25
17
  /**
@@ -34,9 +34,6 @@ function vtkViewNodeFactory(publicAPI, model) {
34
34
  vn.setMyFactory(publicAPI);
35
35
  return vn;
36
36
  };
37
- publicAPI.registerOverride = (className, func) => {
38
- model.overrides[className] = func;
39
- };
40
37
  }
41
38
 
42
39
  // ----------------------------------------------------------------------------
@@ -4,7 +4,7 @@ import vtkForwardPass from './ForwardPass.js';
4
4
  import vtkWebGPUBuffer from './Buffer.js';
5
5
  import vtkWebGPUDevice from './Device.js';
6
6
  import vtkWebGPUHardwareSelector from './HardwareSelector.js';
7
- import vtkWebGPUViewNodeFactory from './ViewNodeFactory.js';
7
+ import vtkWebGPUViewNodeFactory, { registerOverride } from './ViewNodeFactory.js';
8
8
  import vtkRenderPass from '../SceneGraph/RenderPass.js';
9
9
  import vtkRenderWindowViewNode from '../SceneGraph/RenderWindowViewNode.js';
10
10
  import HalfFloat from '../../Common/Core/HalfFloat.js';
@@ -549,9 +549,6 @@ function extend(publicAPI, model) {
549
549
  // Inheritance
550
550
  vtkRenderWindowViewNode.extend(publicAPI, model, initialValues);
551
551
  model.myFactory = vtkWebGPUViewNodeFactory.newInstance();
552
- /* eslint-disable no-use-before-define */
553
- model.myFactory.registerOverride('vtkRenderWindow', newInstance);
554
- /* eslint-enable no-use-before-define */
555
552
 
556
553
  // setup default forward pass rendering
557
554
  model.renderPasses[0] = vtkForwardPass.newInstance();
@@ -589,4 +586,7 @@ var vtkRenderWindow = {
589
586
  extend
590
587
  };
591
588
 
589
+ // Register ourself to WebGPU backend if imported
590
+ registerOverride('vtkRenderWindow', newInstance);
591
+
592
592
  export { vtkRenderWindow as default, extend, newInstance };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kitware/vtk.js",
3
- "version": "30.3.3",
3
+ "version": "30.4.1",
4
4
  "description": "Visualization Toolkit for the Web",
5
5
  "keywords": [
6
6
  "3d",