@kitware/vtk.js 33.0.0-beta.3 → 33.0.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.
Files changed (58) hide show
  1. package/BREAKING_CHANGES.md +0 -3
  2. package/Common/Core/DataArray.d.ts +17 -0
  3. package/Common/Core/DataArray.js +36 -0
  4. package/Common/Core/ScalarsToColors/Constants.js +7 -2
  5. package/Common/Core/ScalarsToColors.js +3 -1
  6. package/Rendering/Core/AbstractImageMapper.d.ts +81 -0
  7. package/Rendering/Core/AbstractImageMapper.js +5 -2
  8. package/Rendering/Core/AbstractPicker.d.ts +13 -13
  9. package/Rendering/Core/AbstractPicker.js +1 -1
  10. package/Rendering/Core/Actor.d.ts +20 -5
  11. package/Rendering/Core/Actor.js +68 -5
  12. package/Rendering/Core/Actor2D.d.ts +22 -0
  13. package/Rendering/Core/Actor2D.js +1 -1
  14. package/Rendering/Core/CellPicker.js +4 -1
  15. package/Rendering/Core/ColorTransferFunction.js +26 -35
  16. package/Rendering/Core/ImageCPRMapper.d.ts +20 -1
  17. package/Rendering/Core/ImageCPRMapper.js +7 -5
  18. package/Rendering/Core/ImageResliceMapper.d.ts +20 -2
  19. package/Rendering/Core/ImageResliceMapper.js +7 -5
  20. package/Rendering/Core/ImageSlice.d.ts +23 -7
  21. package/Rendering/Core/ImageSlice.js +68 -9
  22. package/Rendering/Core/Mapper.js +8 -16
  23. package/Rendering/Core/Prop3D.d.ts +2 -39
  24. package/Rendering/Core/Prop3D.js +2 -81
  25. package/Rendering/Core/ScalarBarActor.js +4 -2
  26. package/Rendering/Core/Viewport.js +13 -3
  27. package/Rendering/Core/Volume.d.ts +20 -5
  28. package/Rendering/Core/Volume.js +70 -2
  29. package/Rendering/Core/VolumeMapper/Constants.d.ts +7 -0
  30. package/Rendering/Core/VolumeMapper/Constants.js +8 -2
  31. package/Rendering/Core/VolumeMapper.d.ts +243 -16
  32. package/Rendering/Core/VolumeMapper.js +60 -20
  33. package/Rendering/Core/VolumeProperty/Constants.d.ts +3 -12
  34. package/Rendering/Core/VolumeProperty/Constants.js +4 -11
  35. package/Rendering/Core/VolumeProperty.d.ts +4 -120
  36. package/Rendering/Core/VolumeProperty.js +4 -49
  37. package/Rendering/Misc/SynchronizableRenderWindow/BehaviorManager/CameraSynchronizer.js +2 -2
  38. package/Rendering/OpenGL/ImageCPRMapper.js +36 -29
  39. package/Rendering/OpenGL/ImageMapper.js +55 -31
  40. package/Rendering/OpenGL/ImageResliceMapper.js +191 -263
  41. package/Rendering/OpenGL/PolyDataMapper.js +8 -1
  42. package/Rendering/OpenGL/RenderWindow/resourceSharingHelper.d.ts +3 -3
  43. package/Rendering/OpenGL/RenderWindow/resourceSharingHelper.js +5 -8
  44. package/Rendering/OpenGL/Renderer.js +1 -1
  45. package/Rendering/OpenGL/Texture.d.ts +29 -8
  46. package/Rendering/OpenGL/Texture.js +154 -23
  47. package/Rendering/OpenGL/VolumeMapper.js +792 -712
  48. package/Rendering/OpenGL/glsl/vtkVolumeFS.glsl.js +1 -1
  49. package/Rendering/SceneGraph/ViewNode.js +12 -2
  50. package/Rendering/WebGPU/VolumePassFSQ.js +2 -2
  51. package/Rendering/WebXR/RenderWindowHelper.js +9 -0
  52. package/Widgets/Core/WidgetManager.d.ts +12 -1
  53. package/Widgets/Representations/WidgetRepresentation.d.ts +1 -7
  54. package/Widgets/Widgets3D/ResliceCursorWidget.d.ts +1 -8
  55. package/index.d.ts +0 -1
  56. package/macros2.js +1 -1
  57. package/package.json +11 -11
  58. package/Interaction/Manipulators/KeyboardCameraManipulator.d.ts +0 -113
@@ -13,7 +13,7 @@ import vtkReplacementShaderMapper from './ReplacementShaderMapper.js';
13
13
  import vtkShaderProgram from './ShaderProgram.js';
14
14
  import vtkTransform from '../../Common/Transform/Transform.js';
15
15
  import vtkViewNode from '../SceneGraph/ViewNode.js';
16
- import { getImageDataHash, getTransferFunctionsHash } from './RenderWindow/resourceSharingHelper.js';
16
+ import { getImageDataHash, getTransferFunctionHash } from './RenderWindow/resourceSharingHelper.js';
17
17
  import { v as vtkImageResliceMapperVS } from './glsl/vtkImageResliceMapperVS.glsl.js';
18
18
  import { v as vtkImageResliceMapperFS } from './glsl/vtkImageResliceMapperFS.glsl.js';
19
19
  import { Filter } from './Texture/Constants.js';
@@ -49,43 +49,8 @@ function safeMatrixMultiply(matrixArray, matrixType, tmpMat) {
49
49
  function vtkOpenGLImageResliceMapper(publicAPI, model) {
50
50
  // Set our className
51
51
  model.classHierarchy.push('vtkOpenGLImageResliceMapper');
52
-
53
- // Associate a reference counter to each graphics resource
54
- const graphicsResourceReferenceCount = new Map();
55
- function decreaseGraphicsResourceCount(openGLRenderWindow, coreObject) {
56
- if (!coreObject) {
57
- return;
58
- }
59
- const oldCount = graphicsResourceReferenceCount.get(coreObject) ?? 0;
60
- const newCount = oldCount - 1;
61
- if (newCount <= 0) {
62
- openGLRenderWindow.unregisterGraphicsResourceUser(coreObject, publicAPI);
63
- graphicsResourceReferenceCount.delete(coreObject);
64
- } else {
65
- graphicsResourceReferenceCount.set(coreObject, newCount);
66
- }
67
- }
68
- function increaseGraphicsResourceCount(openGLRenderWindow, coreObject) {
69
- if (!coreObject) {
70
- return;
71
- }
72
- const oldCount = graphicsResourceReferenceCount.get(coreObject) ?? 0;
73
- const newCount = oldCount + 1;
74
- graphicsResourceReferenceCount.set(coreObject, newCount);
75
- if (oldCount <= 0) {
76
- openGLRenderWindow.registerGraphicsResourceUser(coreObject, publicAPI);
77
- }
78
- }
79
- function replaceGraphicsResource(openGLRenderWindow, oldResourceCoreObject, newResourceCoreObject) {
80
- if (oldResourceCoreObject === newResourceCoreObject) {
81
- return;
82
- }
83
- decreaseGraphicsResourceCount(openGLRenderWindow, oldResourceCoreObject);
84
- increaseGraphicsResourceCount(openGLRenderWindow, newResourceCoreObject);
85
- }
86
52
  function unregisterGraphicsResources(renderWindow) {
87
- // Convert to an array using the spread operator as Firefox doesn't support Iterator.forEach()
88
- [...graphicsResourceReferenceCount.keys()].forEach(coreObject => renderWindow.unregisterGraphicsResourceUser(coreObject, publicAPI));
53
+ [model._scalars, model._colorTransferFunc, model._pwFunc].forEach(coreObject => renderWindow.unregisterGraphicsResourceUser(coreObject, publicAPI));
89
54
  }
90
55
  publicAPI.buildPass = prepass => {
91
56
  if (prepass) {
@@ -145,28 +110,11 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
145
110
  type: 'StartEvent'
146
111
  });
147
112
  model.renderable.update();
148
- const numberOfInputs = model.renderable.getNumberOfInputPorts();
149
- model.currentValidInputs = [];
150
- for (let inputIndex = 0; inputIndex < numberOfInputs; ++inputIndex) {
151
- const imageData = model.renderable.getInputData(inputIndex);
152
- if (imageData && !imageData.isDeleted()) {
153
- model.currentValidInputs.push({
154
- imageData,
155
- inputIndex
156
- });
157
- }
158
- }
159
- const numberOfValidInputs = model.currentValidInputs.length;
160
- if (numberOfValidInputs <= 0) {
113
+ model.currentInput = model.renderable.getInputData();
114
+ if (!model.currentInput) {
161
115
  vtkErrorMacro('No input!');
162
116
  return;
163
117
  }
164
-
165
- // Number of components
166
- const firstImageData = model.currentValidInputs[0].imageData;
167
- const firstScalars = firstImageData.getPointData().getScalars();
168
- model.multiTexturePerVolumeEnabled = numberOfValidInputs > 1;
169
- model.numberOfComponents = model.multiTexturePerVolumeEnabled ? numberOfValidInputs : firstScalars.getNumberOfComponents();
170
118
  publicAPI.updateResliceGeometry();
171
119
  publicAPI.renderPieceStart(ren, actor);
172
120
  publicAPI.renderPieceDraw(ren, actor);
@@ -178,35 +126,17 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
178
126
  publicAPI.renderPieceStart = (ren, actor) => {
179
127
  // make sure the BOs are up to date
180
128
  publicAPI.updateBufferObjects(ren, actor);
181
-
182
- // Update filters for scalar textures
183
- const actorProperties = actor.getProperties();
184
- model.currentValidInputs.forEach(_ref => {
185
- let {
186
- inputIndex
187
- } = _ref;
188
- const actorProperty = actorProperties[inputIndex];
189
- const interpolationType = actorProperty.getInterpolationType();
190
- const scalarTexture = model.scalarTextures[inputIndex];
191
- if (interpolationType === InterpolationType.NEAREST) {
192
- scalarTexture.setMinificationFilter(Filter.NEAREST);
193
- scalarTexture.setMagnificationFilter(Filter.NEAREST);
194
- } else {
195
- scalarTexture.setMinificationFilter(Filter.LINEAR);
196
- scalarTexture.setMagnificationFilter(Filter.LINEAR);
197
- }
198
- });
199
-
200
- // Update color and opacity texture filters
201
- const firstValidInput = model.currentValidInputs[0];
202
- const firstProperty = actorProperties[firstValidInput.inputIndex];
203
- const iType = firstProperty.getInterpolationType();
129
+ const iType = actor.getProperty().getInterpolationType();
204
130
  if (iType === InterpolationType.NEAREST) {
131
+ model.openGLTexture.setMinificationFilter(Filter.NEAREST);
132
+ model.openGLTexture.setMagnificationFilter(Filter.NEAREST);
205
133
  model.colorTexture.setMinificationFilter(Filter.NEAREST);
206
134
  model.colorTexture.setMagnificationFilter(Filter.NEAREST);
207
135
  model.pwfTexture.setMinificationFilter(Filter.NEAREST);
208
136
  model.pwfTexture.setMagnificationFilter(Filter.NEAREST);
209
137
  } else {
138
+ model.openGLTexture.setMinificationFilter(Filter.LINEAR);
139
+ model.openGLTexture.setMagnificationFilter(Filter.LINEAR);
210
140
  model.colorTexture.setMinificationFilter(Filter.LINEAR);
211
141
  model.colorTexture.setMagnificationFilter(Filter.LINEAR);
212
142
  model.pwfTexture.setMinificationFilter(Filter.LINEAR);
@@ -220,8 +150,9 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
220
150
  const gl = model.context;
221
151
 
222
152
  // render the texture
223
- const allTextures = [...model.scalarTextures, model.colorTexture, model.pwfTexture];
224
- allTextures.forEach(texture => texture.activate());
153
+ model.openGLTexture.activate();
154
+ model.colorTexture.activate();
155
+ model.pwfTexture.activate();
225
156
 
226
157
  // update shaders if required
227
158
  publicAPI.updateShaders(model.tris, ren, actor);
@@ -229,7 +160,9 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
229
160
  // Finally draw
230
161
  gl.drawArrays(gl.TRIANGLES, 0, model.tris.getCABO().getElementCount());
231
162
  model.tris.getVAO().release();
232
- allTextures.forEach(texture => texture.deactivate());
163
+ model.openGLTexture.deactivate();
164
+ model.colorTexture.deactivate();
165
+ model.pwfTexture.deactivate();
233
166
  };
234
167
  publicAPI.renderPieceFinish = (ren, actor) => {};
235
168
  publicAPI.updateBufferObjects = (ren, actor) => {
@@ -238,63 +171,70 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
238
171
  publicAPI.buildBufferObjects(ren, actor);
239
172
  }
240
173
  };
241
- publicAPI.getNeedToRebuildBufferObjects = (ren, actor) => model.VBOBuildTime.getMTime() < publicAPI.getMTime() || model.VBOBuildTime.getMTime() < actor.getMTime() || model.VBOBuildTime.getMTime() < model.renderable.getMTime() || model.VBOBuildTime.getMTime() < actor.getProperty(model.currentValidInputs[0].inputIndex)?.getMTime() || model.currentValidInputs.some(_ref2 => {
242
- let {
243
- imageData
244
- } = _ref2;
245
- return model.VBOBuildTime.getMTime() < imageData.getMTime();
246
- }) || model.VBOBuildTime.getMTime() < model.resliceGeom.getMTime() || model.scalarTextures.length !== model.currentValidInputs.length || !model.scalarTextures.every(texture => !!texture?.getHandle()) || !model.colorTexture?.getHandle() || !model.pwfTexture?.getHandle();
174
+ publicAPI.getNeedToRebuildBufferObjects = (ren, actor) => model.VBOBuildTime.getMTime() < publicAPI.getMTime() || model.VBOBuildTime.getMTime() < actor.getMTime() || model.VBOBuildTime.getMTime() < model.renderable.getMTime() || model.VBOBuildTime.getMTime() < actor.getProperty().getMTime() || model.VBOBuildTime.getMTime() < model.currentInput.getMTime() || model.VBOBuildTime.getMTime() < model.resliceGeom.getMTime() || !model.openGLTexture?.getHandle() || !model.colorTexture?.getHandle() || !model.pwfTexture?.getHandle();
247
175
  publicAPI.buildBufferObjects = (ren, actor) => {
248
- model.currentValidInputs.forEach((_ref3, component) => {
249
- let {
250
- imageData
251
- } = _ref3;
252
- // rebuild the scalarTexture if the data has changed
253
- const scalars = imageData.getPointData().getScalars();
254
- const tex = model._openGLRenderWindow.getGraphicsResourceForObject(scalars);
255
- const scalarsHash = getImageDataHash(imageData, scalars);
256
- const reBuildTex = !tex?.oglObject?.getHandle() || tex?.hash !== scalarsHash;
257
- if (reBuildTex) {
258
- const newScalarTexture = vtkOpenGLTexture.newInstance();
259
- newScalarTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
260
- // Build the textures
261
- const dims = imageData.getDimensions();
262
- // Use norm16 for scalar texture if the extension is available
263
- newScalarTexture.setOglNorm16Ext(model.context.getExtension('EXT_texture_norm16'));
264
- newScalarTexture.resetFormatAndType();
265
- newScalarTexture.create3DFilterableFromDataArray(dims[0], dims[1], dims[2], scalars);
266
- model._openGLRenderWindow.setGraphicsResourceForObject(scalars, newScalarTexture, scalarsHash);
267
- model.scalarTextures[component] = newScalarTexture;
268
- } else {
269
- model.scalarTextures[component] = tex.oglObject;
270
- }
271
- replaceGraphicsResource(model._openGLRenderWindow, model._scalarTexturesCore[component], scalars);
272
- model._scalarTexturesCore[component] = scalars;
273
- });
274
- const firstValidInput = model.currentValidInputs[0];
275
- const actorProperties = actor.getProperties();
276
- const firstActorProperty = actorProperties[firstValidInput.inputIndex];
277
- const iComps = firstActorProperty.getIndependentComponents();
278
- const numIComps = iComps ? model.numberOfComponents : 1;
279
- const textureHeight = iComps ? 2 * numIComps : 1;
280
- const colorTransferFunctions = [];
281
- for (let component = 0; component < numIComps; ++component) {
282
- colorTransferFunctions.push(firstActorProperty.getRGBTransferFunction(component));
176
+ const image = model.currentInput;
177
+ if (!image) {
178
+ return;
283
179
  }
284
- const colorFuncHash = getTransferFunctionsHash(colorTransferFunctions, iComps, numIComps);
285
- const firstColorTransferFunc = firstActorProperty.getRGBTransferFunction();
286
- const cTex = model._openGLRenderWindow.getGraphicsResourceForObject(firstColorTransferFunc);
287
- const reBuildC = !cTex?.oglObject?.getHandle() || cTex?.hash !== colorFuncHash;
180
+ const scalars = image.getPointData()?.getScalars();
181
+ if (!scalars) {
182
+ return;
183
+ }
184
+ const numComp = scalars.getNumberOfComponents();
185
+ let toString = getImageDataHash(image, scalars);
186
+ const tex = model._openGLRenderWindow.getGraphicsResourceForObject(scalars);
187
+ const reBuildTex = !tex?.oglObject?.getHandle() || tex?.hash !== toString;
188
+ const updatedExtents = model.renderable.getUpdatedExtents();
189
+ const hasUpdatedExtents = !!updatedExtents.length;
190
+ if (reBuildTex && !hasUpdatedExtents) {
191
+ model.openGLTexture = vtkOpenGLTexture.newInstance();
192
+ model.openGLTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
193
+ // Build the image scalar texture
194
+ // Use norm16 for the 3D texture if the extension is available
195
+ model.openGLTexture.setOglNorm16Ext(model.context.getExtension('EXT_texture_norm16'));
196
+ model.openGLTexture.resetFormatAndType();
197
+
198
+ // Build the image scalar texture
199
+ const dims = image.getDimensions();
200
+ model.openGLTexture.create3DFilterableFromDataArray(dims[0], dims[1], dims[2], scalars, false, updatedExtents);
201
+ model._openGLRenderWindow.setGraphicsResourceForObject(scalars, model.openGLTexture, toString);
202
+ if (scalars !== model._scalars) {
203
+ model._openGLRenderWindow.registerGraphicsResourceUser(scalars, publicAPI);
204
+ model._openGLRenderWindow.unregisterGraphicsResourceUser(model._scalars, publicAPI);
205
+ }
206
+ model._scalars = scalars;
207
+ } else {
208
+ model.openGLTexture = tex.oglObject;
209
+ }
210
+ if (hasUpdatedExtents) {
211
+ // If hasUpdatedExtents, then the texture is partially updated.
212
+ // clear the array to acknowledge the update.
213
+ model.renderable.setUpdatedExtents([]);
214
+ const dims = image.getDimensions();
215
+ model.openGLTexture.create3DFilterableFromDataArray(dims[0], dims[1], dims[2], scalars, false, updatedExtents);
216
+ }
217
+ const ppty = actor.getProperty();
218
+ const iComps = ppty.getIndependentComponents();
219
+ const numIComps = iComps ? numComp : 1;
220
+ const textureHeight = iComps ? 2 * numIComps : 1;
221
+ const colorTransferFunc = ppty.getRGBTransferFunction();
222
+ toString = getTransferFunctionHash(colorTransferFunc, iComps, numIComps);
223
+ const cTex = model._openGLRenderWindow.getGraphicsResourceForObject(colorTransferFunc);
224
+ const reBuildC = !cTex?.oglObject?.getHandle() || cTex?.hash !== toString;
288
225
  if (reBuildC) {
289
- const cWidth = 1024;
226
+ let cWidth = model.renderable.getColorTextureWidth();
227
+ if (cWidth <= 0) {
228
+ cWidth = model.context.getParameter(model.context.MAX_TEXTURE_SIZE);
229
+ }
290
230
  const cSize = cWidth * textureHeight * 3;
291
231
  const cTable = new Uint8ClampedArray(cSize);
292
- const newColorTexture = vtkOpenGLTexture.newInstance();
293
- newColorTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
294
- if (firstColorTransferFunc) {
232
+ model.colorTexture = vtkOpenGLTexture.newInstance();
233
+ model.colorTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
234
+ if (colorTransferFunc) {
295
235
  const tmpTable = new Float32Array(cWidth * 3);
296
236
  for (let c = 0; c < numIComps; c++) {
297
- const cfun = firstActorProperty.getRGBTransferFunction(c);
237
+ const cfun = ppty.getRGBTransferFunction(c);
298
238
  const cRange = cfun.getRange();
299
239
  cfun.getTable(cRange[0], cRange[1], cWidth, tmpTable, 1);
300
240
  if (iComps) {
@@ -304,57 +244,55 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
304
244
  }
305
245
  } else {
306
246
  for (let i = 0; i < cWidth * 3; i++) {
307
- cTable[c * cWidth * 3 + i] = 255.0 * tmpTable[i];
247
+ cTable[c * cWidth * 6 + i] = 255.0 * tmpTable[i];
308
248
  }
309
249
  }
310
250
  }
311
- newColorTexture.resetFormatAndType();
312
- newColorTexture.create2DFromRaw(cWidth, textureHeight, 3, VtkDataTypes.UNSIGNED_CHAR, cTable);
251
+ model.colorTexture.resetFormatAndType();
252
+ model.colorTexture.create2DFromRaw(cWidth, textureHeight, 3, VtkDataTypes.UNSIGNED_CHAR, cTable);
313
253
  } else {
314
- for (let column = 0; column < cWidth * 3; ++column) {
315
- const opacity = 255.0 * column / ((cWidth - 1) * 3);
316
- for (let row = 0; row < textureHeight; ++row) {
317
- // R, G, B
318
- cTable[row * cWidth * 3 + column + 0] = opacity;
319
- cTable[row * cWidth * 3 + column + 1] = opacity;
320
- cTable[row * cWidth * 3 + column + 2] = opacity;
321
- }
254
+ for (let i = 0; i < cWidth * 3; ++i) {
255
+ cTable[i] = 255.0 * i / ((cWidth - 1) * 3);
256
+ cTable[i + 1] = 255.0 * i / ((cWidth - 1) * 3);
257
+ cTable[i + 2] = 255.0 * i / ((cWidth - 1) * 3);
322
258
  }
323
- newColorTexture.resetFormatAndType();
324
- newColorTexture.create2DFromRaw(cWidth, 1, 3, VtkDataTypes.UNSIGNED_CHAR, cTable);
325
- }
326
- if (firstColorTransferFunc) {
327
- model._openGLRenderWindow.setGraphicsResourceForObject(firstColorTransferFunc, newColorTexture, colorFuncHash);
259
+ model.colorTexture.resetFormatAndType();
260
+ model.colorTexture.create2DFromRaw(cWidth, 1, 3, VtkDataTypes.UNSIGNED_CHAR, cTable);
261
+ }
262
+ if (colorTransferFunc) {
263
+ model._openGLRenderWindow.setGraphicsResourceForObject(colorTransferFunc, model.colorTexture, toString);
264
+ if (colorTransferFunc !== model._colorTransferFunc) {
265
+ model._openGLRenderWindow.registerGraphicsResourceUser(colorTransferFunc, publicAPI);
266
+ model._openGLRenderWindow.unregisterGraphicsResourceUser(model._colorTransferFunc, publicAPI);
267
+ }
268
+ model._colorTransferFunc = colorTransferFunc;
328
269
  }
329
- model.colorTexture = newColorTexture;
330
270
  } else {
331
271
  model.colorTexture = cTex.oglObject;
332
272
  }
333
- replaceGraphicsResource(model._openGLRenderWindow, model._colorTextureCore, firstColorTransferFunc);
334
- model._colorTextureCore = firstColorTransferFunc;
335
273
 
336
274
  // Build piecewise function buffer. This buffer is used either
337
275
  // for component weighting or opacity, depending on whether we're
338
276
  // rendering components independently or not.
339
- const opacityFunctions = [];
340
- for (let component = 0; component < numIComps; ++component) {
341
- opacityFunctions.push(firstActorProperty.getPiecewiseFunction(component));
342
- }
343
- const opacityFuncHash = getTransferFunctionsHash(opacityFunctions, iComps, numIComps);
344
- const firstPwFunc = firstActorProperty.getPiecewiseFunction();
345
- const pwfTex = model._openGLRenderWindow.getGraphicsResourceForObject(firstPwFunc);
346
- const reBuildPwf = !pwfTex?.oglObject?.getHandle() || pwfTex?.hash !== opacityFuncHash;
277
+ const pwFunc = ppty.getPiecewiseFunction();
278
+ toString = getTransferFunctionHash(pwFunc, iComps, numIComps);
279
+ const pwfTex = model._openGLRenderWindow.getGraphicsResourceForObject(pwFunc);
280
+ // rebuild opacity tfun?
281
+ const reBuildPwf = !pwfTex?.oglObject?.getHandle() || pwfTex?.hash !== toString;
347
282
  if (reBuildPwf) {
348
- const pwfWidth = 1024;
283
+ let pwfWidth = model.renderable.getOpacityTextureWidth();
284
+ if (pwfWidth <= 0) {
285
+ pwfWidth = model.context.getParameter(model.context.MAX_TEXTURE_SIZE);
286
+ }
349
287
  const pwfSize = pwfWidth * textureHeight;
350
288
  const pwfTable = new Uint8ClampedArray(pwfSize);
351
- const newOpacityTexture = vtkOpenGLTexture.newInstance();
352
- newOpacityTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
353
- if (firstPwFunc) {
289
+ model.pwfTexture = vtkOpenGLTexture.newInstance();
290
+ model.pwfTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
291
+ if (pwFunc) {
354
292
  const pwfFloatTable = new Float32Array(pwfSize);
355
293
  const tmpTable = new Float32Array(pwfWidth);
356
294
  for (let c = 0; c < numIComps; ++c) {
357
- const pwfun = firstActorProperty.getPiecewiseFunction(c);
295
+ const pwfun = ppty.getPiecewiseFunction(c);
358
296
  if (pwfun === null) {
359
297
  // Piecewise constant max if no function supplied for this component
360
298
  pwfFloatTable.fill(1.0);
@@ -369,28 +307,30 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
369
307
  }
370
308
  } else {
371
309
  for (let i = 0; i < pwfWidth; i++) {
372
- pwfFloatTable[i] = tmpTable[i];
310
+ pwfFloatTable[c * pwfWidth * 2 + i] = tmpTable[i];
373
311
  }
374
312
  }
375
313
  }
376
314
  }
377
- newOpacityTexture.resetFormatAndType();
378
- newOpacityTexture.create2DFromRaw(pwfWidth, textureHeight, 1, VtkDataTypes.FLOAT, pwfFloatTable);
315
+ model.pwfTexture.resetFormatAndType();
316
+ model.pwfTexture.create2DFromRaw(pwfWidth, textureHeight, 1, VtkDataTypes.FLOAT, pwfFloatTable);
379
317
  } else {
380
318
  // default is opaque
381
319
  pwfTable.fill(255.0);
382
- newOpacityTexture.resetFormatAndType();
383
- newOpacityTexture.create2DFromRaw(pwfWidth, textureHeight, 1, VtkDataTypes.UNSIGNED_CHAR, pwfTable);
384
- }
385
- if (firstPwFunc) {
386
- model._openGLRenderWindow.setGraphicsResourceForObject(firstPwFunc, newOpacityTexture, opacityFuncHash);
320
+ model.pwfTexture.resetFormatAndType();
321
+ model.pwfTexture.create2DFromRaw(pwfWidth, 1, 1, VtkDataTypes.UNSIGNED_CHAR, pwfTable);
322
+ }
323
+ if (pwFunc) {
324
+ model._openGLRenderWindow.setGraphicsResourceForObject(pwFunc, model.pwfTexture, toString);
325
+ if (pwFunc !== model._pwFunc) {
326
+ model._openGLRenderWindow.registerGraphicsResourceUser(pwFunc, publicAPI);
327
+ model._openGLRenderWindow.unregisterGraphicsResourceUser(model._pwFunc, publicAPI);
328
+ }
329
+ model._pwFunc = pwFunc;
387
330
  }
388
- model.pwfTexture = newOpacityTexture;
389
331
  } else {
390
332
  model.pwfTexture = pwfTex.oglObject;
391
333
  }
392
- replaceGraphicsResource(model._openGLRenderWindow, model._pwfTextureCore, firstPwFunc);
393
- model._pwfTextureCore = firstPwFunc;
394
334
  const vboString = `${model.resliceGeom.getMTime()}A${model.renderable.getSlabThickness()}`;
395
335
  if (!model.tris.getCABO().getElementCount() || model.VBOBuildString !== vboString) {
396
336
  const points = vtkDataArray.newInstance({
@@ -451,12 +391,11 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
451
391
  };
452
392
  publicAPI.setMapperShaderParameters = (cellBO, ren, actor) => {
453
393
  const program = cellBO.getProgram();
454
- const firstImageData = model.currentValidInputs[0].imageData;
455
394
  if (cellBO.getCABO().getElementCount() && (model.VBOBuildTime.getMTime() > cellBO.getAttributeUpdateTime().getMTime() || cellBO.getShaderSourceTime().getMTime() > cellBO.getAttributeUpdateTime().getMTime())) {
456
395
  // Set the 3D texture
457
- model.scalarTextures.forEach((scalarTexture, component) => {
458
- program.setUniformi(`volumeTexture[${component}]`, scalarTexture.getTextureUnit());
459
- });
396
+ if (program.isUniformUsed('texture1')) {
397
+ program.setUniformi('texture1', model.openGLTexture.getTextureUnit());
398
+ }
460
399
 
461
400
  // Set the plane vertex attributes
462
401
  if (program.isAttributeUsed('vertexWC')) {
@@ -475,7 +414,7 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
475
414
  program.setUniformf('slabThickness', model.renderable.getSlabThickness());
476
415
  }
477
416
  if (program.isUniformUsed('spacing')) {
478
- program.setUniform3fv('spacing', firstImageData.getSpacing());
417
+ program.setUniform3fv('spacing', model.currentInput.getSpacing());
479
418
  }
480
419
  if (program.isUniformUsed('slabType')) {
481
420
  program.setUniformi('slabType', model.renderable.getSlabType());
@@ -491,8 +430,9 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
491
430
 
492
431
  // Set the world->texture matrix
493
432
  if (program.isUniformUsed('WCTCMatrix')) {
494
- const dim = firstImageData.getDimensions();
495
- mat4.copy(model.tmpMat4, firstImageData.getIndexToWorld());
433
+ const image = model.currentInput;
434
+ const dim = image.getDimensions();
435
+ mat4.copy(model.tmpMat4, image.getIndexToWorld());
496
436
  mat4.translate(model.tmpMat4, model.tmpMat4, [-0.5, -0.5, -0.5]);
497
437
  mat4.scale(model.tmpMat4, model.tmpMat4, dim);
498
438
  mat4.invert(model.tmpMat4, model.tmpMat4);
@@ -541,8 +481,8 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
541
481
  };
542
482
  publicAPI.setPropertyShaderParameters = (cellBO, ren, actor) => {
543
483
  const program = cellBO.getProgram();
544
- const firstPpty = actor.getProperty(model.currentValidInputs[0].inputIndex);
545
- const opacity = firstPpty.getOpacity();
484
+ const ppty = actor.getProperty();
485
+ const opacity = ppty.getOpacity();
546
486
  program.setUniformf('opacity', opacity);
547
487
 
548
488
  // Component mix
@@ -551,56 +491,53 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
551
491
  // - 2 comps => LA
552
492
  // - 3 comps => RGB + opacity from pwf
553
493
  // - 4 comps => RGBA
554
- const numComp = model.numberOfComponents;
555
- const iComps = firstPpty.getIndependentComponents();
494
+ const numComp = model.openGLTexture.getComponents();
495
+ const iComps = ppty.getIndependentComponents();
556
496
  if (iComps) {
557
497
  for (let i = 0; i < numComp; ++i) {
558
- program.setUniformf(`mix${i}`, firstPpty.getComponentWeight(i));
498
+ program.setUniformf(`mix${i}`, ppty.getComponentWeight(i));
559
499
  }
560
500
  }
561
501
 
502
+ // Color opacity map
503
+ const volInfo = model.openGLTexture.getVolumeInfo();
504
+
562
505
  // three levels of shift scale combined into one
563
506
  // for performance in the fragment shader
564
- for (let component = 0; component < numComp; component++) {
565
- const useMultiTexture = model.multiTexturePerVolumeEnabled;
566
- const textureIndex = useMultiTexture ? component : 0;
567
- const volInfoIndex = useMultiTexture ? 0 : component;
568
- const scalarTexture = model.scalarTextures[textureIndex];
569
- const volInfo = scalarTexture.getVolumeInfo();
570
- const volScale = volInfo.scale[volInfoIndex];
571
- const volOffset = volInfo.offset[volInfoIndex];
572
- const target = iComps ? component : 0;
573
-
574
- // color shift/scale
575
- let cw = firstPpty.getColorWindow();
576
- let cl = firstPpty.getColorLevel();
577
- const cfun = firstPpty.getRGBTransferFunction(target);
578
- if (cfun && firstPpty.getUseLookupTableScalarRange()) {
507
+ for (let i = 0; i < numComp; i++) {
508
+ let cw = ppty.getColorWindow();
509
+ let cl = ppty.getColorLevel();
510
+ const target = iComps ? i : 0;
511
+ const cfun = ppty.getRGBTransferFunction(target);
512
+ if (cfun && ppty.getUseLookupTableScalarRange()) {
579
513
  const cRange = cfun.getRange();
580
514
  cw = cRange[1] - cRange[0];
581
515
  cl = 0.5 * (cRange[1] + cRange[0]);
582
516
  }
583
- const colorScale = volScale / cw;
584
- const colorShift = (volOffset - cl) / cw + 0.5;
585
- program.setUniformf(`cshift${component}`, colorShift);
586
- program.setUniformf(`cscale${component}`, colorScale);
517
+ const scale = volInfo.scale[i] / cw;
518
+ const shift = (volInfo.offset[i] - cl) / cw + 0.5;
519
+ program.setUniformf(`cshift${i}`, shift);
520
+ program.setUniformf(`cscale${i}`, scale);
521
+ }
522
+ const texColorUnit = model.colorTexture.getTextureUnit();
523
+ program.setUniformi('colorTexture1', texColorUnit);
587
524
 
588
- // pwf shift/scale
525
+ // pwf shift/scale
526
+ for (let i = 0; i < numComp; i++) {
589
527
  let pwfScale = 1.0;
590
528
  let pwfShift = 0.0;
591
- const pwfun = firstPpty.getPiecewiseFunction(target);
529
+ const target = iComps ? i : 0;
530
+ const pwfun = ppty.getPiecewiseFunction(target);
592
531
  if (pwfun) {
593
532
  const pwfRange = pwfun.getRange();
594
533
  const length = pwfRange[1] - pwfRange[0];
595
534
  const mid = 0.5 * (pwfRange[0] + pwfRange[1]);
596
- pwfScale = volScale / length;
597
- pwfShift = (volOffset - mid) / length + 0.5;
535
+ pwfScale = volInfo.scale[i] / length;
536
+ pwfShift = (volInfo.offset[i] - mid) / length + 0.5;
598
537
  }
599
- program.setUniformf(`pwfshift${component}`, pwfShift);
600
- program.setUniformf(`pwfscale${component}`, pwfScale);
538
+ program.setUniformf(`pwfshift${i}`, pwfShift);
539
+ program.setUniformf(`pwfscale${i}`, pwfScale);
601
540
  }
602
- const texColorUnit = model.colorTexture.getTextureUnit();
603
- program.setUniformi('colorTexture1', texColorUnit);
604
541
  const texOpacityUnit = model.pwfTexture.getTextureUnit();
605
542
  program.setUniformi('pwfTexture1', texOpacityUnit);
606
543
 
@@ -614,7 +551,8 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
614
551
  // input modified
615
552
  // light complexity changed
616
553
  // render pass shader replacement changed
617
- const iComp = actor.getProperty(model.currentValidInputs[0].inputIndex).getIndependentComponents();
554
+ const tNumComp = model.openGLTexture.getComponents();
555
+ const iComp = actor.getProperty().getIndependentComponents();
618
556
  const slabTh = model.renderable.getSlabThickness();
619
557
  const slabType = model.renderable.getSlabType();
620
558
  const slabTrap = model.renderable.getSlabTrapezoidIntegration();
@@ -624,10 +562,9 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
624
562
  if (!model.currentRenderPass && model.lastRenderPassShaderReplacement || model.currentRenderPass && model.currentRenderPass.getShaderReplacement() !== model.lastRenderPassShaderReplacement) {
625
563
  needRebuild = true;
626
564
  }
627
- if (needRebuild || model.lastHaveSeenDepthRequest !== model.haveSeenDepthRequest || model.lastNumberOfComponents !== model.numberOfComponents || model.lastMultiTexturePerVolumeEnabled !== model.multiTexturePerVolumeEnabled || cellBO.getProgram()?.getHandle() === 0 || model.lastIndependentComponents !== iComp || model.lastSlabThickness !== slabTh || model.lastSlabType !== slabType || model.lastSlabTrapezoidIntegration !== slabTrap) {
565
+ if (needRebuild || model.lastHaveSeenDepthRequest !== model.haveSeenDepthRequest || cellBO.getProgram()?.getHandle() === 0 || model.lastTextureComponents !== tNumComp || model.lastIndependentComponents !== iComp || model.lastSlabThickness !== slabTh || model.lastSlabType !== slabType || model.lastSlabTrapezoidIntegration !== slabTrap) {
628
566
  model.lastHaveSeenDepthRequest = model.haveSeenDepthRequest;
629
- model.lastNumberOfComponents = model.numberOfComponents;
630
- model.lastMultiTexturePerVolumeEnabled = model.multiTexturePerVolumeEnabled;
567
+ model.lastTextureComponents = tNumComp;
631
568
  model.lastIndependentComponents = iComp;
632
569
  model.lastSlabThickness = slabTh;
633
570
  model.lastSlabType = slabType;
@@ -661,9 +598,9 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
661
598
  VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::TCoord::Dec', tcoordVSDec).result;
662
599
  const tcoordVSImpl = ['fragTexCoord = (WCTCMatrix * vertexWC).xyz;'];
663
600
  VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::TCoord::Impl', tcoordVSImpl).result;
664
- const tNumComp = model.numberOfComponents;
665
- const iComps = actor.getProperty(model.currentValidInputs[0].inputIndex).getIndependentComponents();
666
- let tcoordFSDec = ['in vec3 fragTexCoord;', `uniform highp sampler3D volumeTexture[${model.scalarTextures.length}];`, 'uniform mat4 WCTCMatrix;',
601
+ const tNumComp = model.openGLTexture.getComponents();
602
+ const iComps = actor.getProperty().getIndependentComponents();
603
+ let tcoordFSDec = ['in vec3 fragTexCoord;', 'uniform highp sampler3D texture1;', 'uniform mat4 WCTCMatrix;',
667
604
  // color shift and scale
668
605
  'uniform float cshift0;', 'uniform float cscale0;',
669
606
  // pwf shift and scale
@@ -674,18 +611,6 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
674
611
  'uniform float opacity;',
675
612
  // background color
676
613
  'uniform vec4 backgroundColor;'];
677
-
678
- // Function to sample texture
679
- tcoordFSDec.push('vec4 rawSampleTexture(vec3 pos) {');
680
- if (!model.multiTexturePerVolumeEnabled) {
681
- tcoordFSDec.push('return texture(volumeTexture[0], pos);', '}');
682
- } else {
683
- tcoordFSDec.push('vec4 rawSample;');
684
- for (let component = 0; component < model.scalarTextures.length; ++component) {
685
- tcoordFSDec.push(`rawSample[${component}] = texture(volumeTexture[${component}], pos)[0];`);
686
- }
687
- tcoordFSDec.push('return rawSample;', '}');
688
- }
689
614
  if (iComps) {
690
615
  for (let comp = 1; comp < tNumComp; comp++) {
691
616
  tcoordFSDec = tcoordFSDec.concat([
@@ -721,14 +646,14 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
721
646
  tcoordFSDec = tcoordFSDec.concat(['vec4 compositeValue(vec4 currVal, vec4 valToComp, int trapezoid)', '{', ' vec4 retVal = vec4(1.0);', ' if (slabType == 0) // min', ' {', ' retVal = min(currVal, valToComp);', ' }', ' else if (slabType == 1) // max', ' {', ' retVal = max(currVal, valToComp);', ' }', ' else if (slabType == 3) // sum', ' {', ' retVal = currVal + (trapezoid > 0 ? 0.5 * valToComp : valToComp); ', ' }', ' else // mean', ' {', ' retVal = currVal + (trapezoid > 0 ? 0.5 * valToComp : valToComp); ', ' }', ' return retVal;', '}']);
722
647
  }
723
648
  FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::TCoord::Dec', tcoordFSDec).result;
724
- let tcoordFSImpl = ['if (any(greaterThan(fragTexCoord, vec3(1.0))) || any(lessThan(fragTexCoord, vec3(0.0))))', '{', ' // set the background color and exit', ' gl_FragData[0] = backgroundColor;', ' return;', '}', 'vec4 tvalue = rawSampleTexture(fragTexCoord);'];
649
+ let tcoordFSImpl = ['if (any(greaterThan(fragTexCoord, vec3(1.0))) || any(lessThan(fragTexCoord, vec3(0.0))))', '{', ' // set the background color and exit', ' gl_FragData[0] = backgroundColor;', ' return;', '}', 'vec4 tvalue = texture(texture1, fragTexCoord);'];
725
650
  if (slabThickness > 0.0) {
726
- tcoordFSImpl = tcoordFSImpl.concat(['// Get the first and last samples', 'int numSlices = 1;', 'float scaling = min(min(spacing.x, spacing.y), spacing.z) * 0.5;', 'vec3 normalxspacing = scaling * normalWCVSOutput;', 'float distTraveled = length(normalxspacing);', 'int trapezoid = 0;', 'while (distTraveled < slabThickness * 0.5)', '{', ' distTraveled += length(normalxspacing);', ' float fnumSlices = float(numSlices);', ' if (distTraveled > slabThickness * 0.5)', ' {', ' // Before stepping outside the slab, sample at the boundaries', ' normalxspacing = normalWCVSOutput * slabThickness * 0.5 / fnumSlices;', ' trapezoid = slabTrapezoid;', ' }', ' vec3 fragTCoordNeg = (WCTCMatrix * vec4(vertexWCVSOutput.xyz - fnumSlices * normalxspacing * vboScaling, 1.0)).xyz;', ' if (!any(greaterThan(fragTCoordNeg, vec3(1.0))) && !any(lessThan(fragTCoordNeg, vec3(0.0))))', ' {', ' vec4 newVal = rawSampleTexture(fragTCoordNeg);', ' tvalue = compositeValue(tvalue, newVal, trapezoid);', ' numSlices += 1;', ' }', ' vec3 fragTCoordPos = (WCTCMatrix * vec4(vertexWCVSOutput.xyz + fnumSlices * normalxspacing * vboScaling, 1.0)).xyz;', ' if (!any(greaterThan(fragTCoordNeg, vec3(1.0))) && !any(lessThan(fragTCoordNeg, vec3(0.0))))', ' {', ' vec4 newVal = rawSampleTexture(fragTCoordPos);', ' tvalue = compositeValue(tvalue, newVal, trapezoid);', ' numSlices += 1;', ' }', '}', '// Finally, if slab type is *mean*, divide the sum by the numSlices', 'if (slabType == 2)', '{', ' tvalue = tvalue / float(numSlices);', '}']);
651
+ tcoordFSImpl = tcoordFSImpl.concat(['// Get the first and last samples', 'int numSlices = 1;', 'float scaling = min(min(spacing.x, spacing.y), spacing.z) * 0.5;', 'vec3 normalxspacing = scaling * normalWCVSOutput;', 'float distTraveled = length(normalxspacing);', 'int trapezoid = 0;', 'while (distTraveled < slabThickness * 0.5)', '{', ' distTraveled += length(normalxspacing);', ' float fnumSlices = float(numSlices);', ' if (distTraveled > slabThickness * 0.5)', ' {', ' // Before stepping outside the slab, sample at the boundaries', ' normalxspacing = normalWCVSOutput * slabThickness * 0.5 / fnumSlices;', ' trapezoid = slabTrapezoid;', ' }', ' vec3 fragTCoordNeg = (WCTCMatrix * vec4(vertexWCVSOutput.xyz - fnumSlices * normalxspacing * vboScaling, 1.0)).xyz;', ' if (!any(greaterThan(fragTCoordNeg, vec3(1.0))) && !any(lessThan(fragTCoordNeg, vec3(0.0))))', ' {', ' vec4 newVal = texture(texture1, fragTCoordNeg);', ' tvalue = compositeValue(tvalue, newVal, trapezoid);', ' numSlices += 1;', ' }', ' vec3 fragTCoordPos = (WCTCMatrix * vec4(vertexWCVSOutput.xyz + fnumSlices * normalxspacing * vboScaling, 1.0)).xyz;', ' if (!any(greaterThan(fragTCoordNeg, vec3(1.0))) && !any(lessThan(fragTCoordNeg, vec3(0.0))))', ' {', ' vec4 newVal = texture(texture1, fragTCoordPos);', ' tvalue = compositeValue(tvalue, newVal, trapezoid);', ' numSlices += 1;', ' }', '}', '// Finally, if slab type is *mean*, divide the sum by the numSlices', 'if (slabType == 2)', '{', ' tvalue = tvalue / float(numSlices);', '}']);
727
652
  }
728
653
  if (iComps) {
729
654
  const rgba = ['r', 'g', 'b', 'a'];
730
655
  for (let comp = 0; comp < tNumComp; ++comp) {
731
- tcoordFSImpl = tcoordFSImpl.concat([`vec3 tcolor${comp} = texture2D(colorTexture1, vec2(tvalue.${rgba[comp]} * cscale${comp} + cshift${comp}, height${comp})).rgb;`, `float compWeight${comp} = mix${comp} * texture2D(pwfTexture1, vec2(tvalue.${rgba[comp]} * pwfscale${comp} + pwfshift${comp}, height${comp})).r;`]);
656
+ tcoordFSImpl = tcoordFSImpl.concat([`vec3 tcolor${comp} = mix${comp} * texture2D(colorTexture1, vec2(tvalue.${rgba[comp]} * cscale${comp} + cshift${comp}, height${comp})).rgb;`, `float compWeight${comp} = mix${comp} * texture2D(pwfTexture1, vec2(tvalue.${rgba[comp]} * pwfscale${comp} + pwfshift${comp}, height${comp})).r;`]);
732
657
  }
733
658
  switch (tNumComp) {
734
659
  case 1:
@@ -814,8 +739,8 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
814
739
  }
815
740
  publicAPI.updateResliceGeometry = () => {
816
741
  let resGeomString = '';
817
- const firstImageData = model.currentValidInputs[0].imageData;
818
- const imageBounds = firstImageData?.getBounds();
742
+ const image = model.currentInput;
743
+ const imageBounds = image?.getBounds();
819
744
  // Orthogonal slicing by default
820
745
  let orthoSlicing = true;
821
746
  let orthoAxis = 2;
@@ -827,11 +752,11 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
827
752
  resGeomString = resGeomString.concat(`Plane${slicePlane.getMTime()}`);
828
753
  // Compute a world-to-image-orientation matrix.
829
754
  const w2io = mat3.create();
830
- if (firstImageData) {
831
- resGeomString = resGeomString.concat(`Image${firstImageData.getMTime()}`);
755
+ if (image) {
756
+ resGeomString = resGeomString.concat(`Image${image.getMTime()}`);
832
757
  // Ignore the translation component since we are
833
758
  // using it on vectors rather than positions.
834
- mat3.set(w2io, ...firstImageData.getDirection());
759
+ mat3.set(w2io, ...image.getDirection());
835
760
  mat3.invert(w2io, w2io);
836
761
  }
837
762
  // Check to see if we can bypass oblique slicing related bounds computation
@@ -844,14 +769,14 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
844
769
  const plane = vtkPlane.newInstance();
845
770
  plane.setNormal(0, 0, 1);
846
771
  let bds = [0, 1, 0, 1, 0, 1];
847
- if (firstImageData) {
772
+ if (image) {
848
773
  bds = imageBounds;
849
774
  }
850
775
  plane.setOrigin(bds[0], bds[2], 0.5 * (bds[5] + bds[4]));
851
776
  model.renderable.setSlicePlane(plane);
852
777
  resGeomString = resGeomString.concat(`Plane${slicePlane?.getMTime()}`);
853
- if (firstImageData) {
854
- resGeomString = resGeomString.concat(`Image${firstImageData.getMTime()}`);
778
+ if (image) {
779
+ resGeomString = resGeomString.concat(`Image${image.getMTime()}`);
855
780
  }
856
781
  }
857
782
  if (!model.resliceGeom || model.resliceGeomUpdateString !== resGeomString) {
@@ -864,7 +789,7 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
864
789
  model.resliceGeom.getPointData().setNormals(slicePD.getPointData().getNormals());
865
790
  } else if (slicePlane) {
866
791
  if (!orthoSlicing) {
867
- model.outlineFilter.setInputData(firstImageData);
792
+ model.outlineFilter.setInputData(image);
868
793
  model.cutter.setInputConnection(model.outlineFilter.getOutputPort());
869
794
  model.cutter.setCutFunction(slicePlane);
870
795
  model.lineToSurfaceFilter.setInputConnection(model.cutter.getOutputPort());
@@ -897,9 +822,9 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
897
822
  // Since the image-local normal is axis-aligned, we
898
823
  // can quickly construct the cutting plane using indexToWorld transforms.
899
824
  const ptsArray = new Float32Array(12);
900
- const indexSpacePlaneOrigin = firstImageData.worldToIndex(slicePlane.getOrigin(), [0, 0, 0]);
825
+ const indexSpacePlaneOrigin = image.worldToIndex(slicePlane.getOrigin(), [0, 0, 0]);
901
826
  const otherAxes = [(orthoAxis + 1) % 3, (orthoAxis + 2) % 3].sort();
902
- const ext = firstImageData.getSpatialExtent();
827
+ const ext = image.getSpatialExtent();
903
828
  let ptIdx = 0;
904
829
  for (let i = 0; i < 2; ++i) {
905
830
  for (let j = 0; j < 2; ++j) {
@@ -909,7 +834,7 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
909
834
  ptIdx += 3;
910
835
  }
911
836
  }
912
- model.transform.setMatrix(firstImageData.getIndexToWorld());
837
+ model.transform.setMatrix(image.getIndexToWorld());
913
838
  model.transform.transformPoints(ptsArray, ptsArray);
914
839
  const cellArray = new Uint16Array(8);
915
840
  cellArray[0] = 3;
@@ -947,9 +872,11 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
947
872
  model.resliceGeom?.modified();
948
873
  }
949
874
  };
950
- publicAPI.setScalarTextures = scalarTextures => {
951
- model.scalarTextures = [...scalarTextures];
952
- model._externalOpenGLTexture = true;
875
+ publicAPI.setOpenGLTexture = oglTex => {
876
+ if (oglTex) {
877
+ model.openGLTexture = oglTex;
878
+ model._externalOpenGLTexture = true;
879
+ }
953
880
  };
954
881
  publicAPI.delete = chain(() => {
955
882
  if (model._openGLRenderWindow) {
@@ -968,21 +895,22 @@ const DEFAULT_VALUES = {
968
895
  haveSeenDepthRequest: false,
969
896
  lastHaveSeenDepthRequest: false,
970
897
  lastIndependentComponents: false,
971
- lastNumberOfComponents: 0,
972
- lastMultiTexturePerVolumeEnabled: false,
898
+ lastTextureComponents: 0,
973
899
  lastSlabThickness: 0,
974
900
  lastSlabTrapezoidIntegration: 0,
975
901
  lastSlabType: -1,
976
- scalarTextures: [],
977
- _scalarTexturesCore: [],
978
- colorTexture: null,
979
- _colorTextureCore: null,
980
- pwfTexture: null,
981
- _pwfTextureCore: null,
982
- _externalOpenGLTexture: false,
902
+ openGLTexture: null,
903
+ colorTextureString: null,
904
+ pwfTextureString: null,
983
905
  resliceGeom: null,
984
906
  resliceGeomUpdateString: null,
985
- tris: null
907
+ tris: null,
908
+ colorTexture: null,
909
+ pwfTexture: null,
910
+ _externalOpenGLTexture: false
911
+ // _scalars: null,
912
+ // _colorTransferFunc: null,
913
+ // _pwFunc: null,
986
914
  };
987
915
 
988
916
  // ----------------------------------------------------------------------------
@@ -996,7 +924,7 @@ function extend(publicAPI, model) {
996
924
  vtkReplacementShaderMapper.implementReplaceShaderCoincidentOffset(publicAPI, model, initialValues);
997
925
  vtkReplacementShaderMapper.implementBuildShadersWithReplacements(publicAPI, model, initialValues);
998
926
  model.tris = vtkHelper.newInstance();
999
- model.scalarTextures = [];
927
+ model.openGLTexture = null;
1000
928
  model.colorTexture = null;
1001
929
  model.pwfTexture = null;
1002
930
  model.VBOBuildTime = {};
@@ -1011,7 +939,7 @@ function extend(publicAPI, model) {
1011
939
  model.cutter = vtkCutter.newInstance();
1012
940
  model.lineToSurfaceFilter = vtkClosedPolyLineToSurfaceFilter.newInstance();
1013
941
  model.transform = vtkTransform.newInstance();
1014
- get(publicAPI, model, ['scalarTextures']);
942
+ get(publicAPI, model, ['openGLTexture']);
1015
943
 
1016
944
  // Object methods
1017
945
  vtkOpenGLImageResliceMapper(publicAPI, model);