@kitware/vtk.js 33.0.0-beta.4 → 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 (41) hide show
  1. package/BREAKING_CHANGES.md +0 -3
  2. package/Common/Core/ScalarsToColors/Constants.js +7 -2
  3. package/Common/Core/ScalarsToColors.js +3 -1
  4. package/Rendering/Core/Actor.d.ts +20 -5
  5. package/Rendering/Core/Actor.js +68 -5
  6. package/Rendering/Core/ColorTransferFunction.js +26 -35
  7. package/Rendering/Core/ImageCPRMapper.d.ts +20 -1
  8. package/Rendering/Core/ImageCPRMapper.js +2 -1
  9. package/Rendering/Core/ImageProperty.d.ts +1 -20
  10. package/Rendering/Core/ImageProperty.js +5 -7
  11. package/Rendering/Core/ImageResliceMapper.d.ts +20 -1
  12. package/Rendering/Core/ImageResliceMapper.js +2 -1
  13. package/Rendering/Core/ImageSlice.d.ts +23 -7
  14. package/Rendering/Core/ImageSlice.js +68 -9
  15. package/Rendering/Core/Mapper.js +8 -16
  16. package/Rendering/Core/Prop3D.d.ts +2 -39
  17. package/Rendering/Core/Prop3D.js +2 -81
  18. package/Rendering/Core/ScalarBarActor.js +4 -2
  19. package/Rendering/Core/Volume.d.ts +20 -5
  20. package/Rendering/Core/Volume.js +70 -2
  21. package/Rendering/Core/VolumeMapper/Constants.d.ts +7 -0
  22. package/Rendering/Core/VolumeMapper/Constants.js +8 -2
  23. package/Rendering/Core/VolumeMapper.d.ts +173 -16
  24. package/Rendering/Core/VolumeMapper.js +51 -16
  25. package/Rendering/Core/VolumeProperty/Constants.d.ts +3 -12
  26. package/Rendering/Core/VolumeProperty/Constants.js +4 -11
  27. package/Rendering/Core/VolumeProperty.d.ts +5 -140
  28. package/Rendering/Core/VolumeProperty.js +7 -54
  29. package/Rendering/OpenGL/ImageCPRMapper.js +21 -30
  30. package/Rendering/OpenGL/ImageMapper.js +27 -27
  31. package/Rendering/OpenGL/ImageResliceMapper.js +183 -271
  32. package/Rendering/OpenGL/PolyDataMapper.js +8 -1
  33. package/Rendering/OpenGL/RenderWindow/resourceSharingHelper.d.ts +3 -3
  34. package/Rendering/OpenGL/RenderWindow/resourceSharingHelper.js +5 -8
  35. package/Rendering/OpenGL/VolumeMapper.js +784 -722
  36. package/Rendering/OpenGL/glsl/vtkVolumeFS.glsl.js +1 -1
  37. package/Rendering/WebGPU/VolumePassFSQ.js +2 -2
  38. package/index.d.ts +0 -1
  39. package/macros2.js +1 -1
  40. package/package.json +1 -1
  41. 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,57 @@ 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
- const actorProperties = actor.getProperties();
249
- model.currentValidInputs.forEach((_ref3, component) => {
250
- let {
251
- imageData
252
- } = _ref3;
253
- // rebuild the scalarTexture if the data has changed
254
- const scalars = imageData.getPointData().getScalars();
255
- const tex = model._openGLRenderWindow.getGraphicsResourceForObject(scalars);
256
- const scalarsHash = getImageDataHash(imageData, scalars);
257
- const reBuildTex = !tex?.oglObject?.getHandle() || tex?.hash !== scalarsHash;
258
- const actorProperty = actorProperties[component];
259
- const updatedExtents = actorProperty.getUpdatedExtents();
260
- const hasUpdatedExtents = !!updatedExtents.length;
261
- if (reBuildTex && !hasUpdatedExtents) {
262
- const newScalarTexture = vtkOpenGLTexture.newInstance();
263
- newScalarTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
264
- // Build the textures
265
- const dims = imageData.getDimensions();
266
- // Use norm16 for scalar texture if the extension is available
267
- newScalarTexture.setOglNorm16Ext(model.context.getExtension('EXT_texture_norm16'));
268
- newScalarTexture.resetFormatAndType();
269
- newScalarTexture.create3DFilterableFromDataArray(dims[0], dims[1], dims[2], scalars);
270
- model._openGLRenderWindow.setGraphicsResourceForObject(scalars, newScalarTexture, scalarsHash);
271
- model.scalarTextures[component] = newScalarTexture;
272
- } else {
273
- model.scalarTextures[component] = tex.oglObject;
274
- }
275
- if (hasUpdatedExtents) {
276
- // If hasUpdatedExtents, then the texture is partially updated.
277
- // clear the array to acknowledge the update.
278
- actorProperty.setUpdatedExtents([]);
279
- const dims = imageData.getDimensions();
280
- model.scalarTextures[component].create3DFilterableFromDataArray(dims[0], dims[1], dims[2], scalars, false, updatedExtents);
281
- }
282
- replaceGraphicsResource(model._openGLRenderWindow, model._scalarTexturesCore[component], scalars);
283
- model._scalarTexturesCore[component] = scalars;
284
- });
285
- const firstValidInput = model.currentValidInputs[0];
286
- const firstActorProperty = actorProperties[firstValidInput.inputIndex];
287
- const iComps = firstActorProperty.getIndependentComponents();
288
- const numIComps = iComps ? model.numberOfComponents : 1;
289
- const textureHeight = iComps ? 2 * numIComps : 1;
290
- const colorTransferFunctions = [];
291
- for (let component = 0; component < numIComps; ++component) {
292
- colorTransferFunctions.push(firstActorProperty.getRGBTransferFunction(component));
176
+ const image = model.currentInput;
177
+ if (!image) {
178
+ return;
179
+ }
180
+ const scalars = image.getPointData()?.getScalars();
181
+ if (!scalars) {
182
+ return;
293
183
  }
294
- const colorFuncHash = getTransferFunctionsHash(colorTransferFunctions, iComps, numIComps);
295
- const firstColorTransferFunc = firstActorProperty.getRGBTransferFunction();
296
- const cTex = model._openGLRenderWindow.getGraphicsResourceForObject(firstColorTransferFunc);
297
- const reBuildC = !cTex?.oglObject?.getHandle() || cTex?.hash !== colorFuncHash;
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;
298
225
  if (reBuildC) {
299
226
  let cWidth = model.renderable.getColorTextureWidth();
300
227
  if (cWidth <= 0) {
@@ -302,12 +229,12 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
302
229
  }
303
230
  const cSize = cWidth * textureHeight * 3;
304
231
  const cTable = new Uint8ClampedArray(cSize);
305
- const newColorTexture = vtkOpenGLTexture.newInstance();
306
- newColorTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
307
- if (firstColorTransferFunc) {
232
+ model.colorTexture = vtkOpenGLTexture.newInstance();
233
+ model.colorTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
234
+ if (colorTransferFunc) {
308
235
  const tmpTable = new Float32Array(cWidth * 3);
309
236
  for (let c = 0; c < numIComps; c++) {
310
- const cfun = firstActorProperty.getRGBTransferFunction(c);
237
+ const cfun = ppty.getRGBTransferFunction(c);
311
238
  const cRange = cfun.getRange();
312
239
  cfun.getTable(cRange[0], cRange[1], cWidth, tmpTable, 1);
313
240
  if (iComps) {
@@ -317,46 +244,41 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
317
244
  }
318
245
  } else {
319
246
  for (let i = 0; i < cWidth * 3; i++) {
320
- cTable[c * cWidth * 3 + i] = 255.0 * tmpTable[i];
247
+ cTable[c * cWidth * 6 + i] = 255.0 * tmpTable[i];
321
248
  }
322
249
  }
323
250
  }
324
- newColorTexture.resetFormatAndType();
325
- newColorTexture.create2DFromRaw(cWidth, textureHeight, 3, VtkDataTypes.UNSIGNED_CHAR, cTable);
251
+ model.colorTexture.resetFormatAndType();
252
+ model.colorTexture.create2DFromRaw(cWidth, textureHeight, 3, VtkDataTypes.UNSIGNED_CHAR, cTable);
326
253
  } else {
327
- for (let column = 0; column < cWidth * 3; ++column) {
328
- const opacity = 255.0 * column / ((cWidth - 1) * 3);
329
- for (let row = 0; row < textureHeight; ++row) {
330
- // R, G, B
331
- cTable[row * cWidth * 3 + column + 0] = opacity;
332
- cTable[row * cWidth * 3 + column + 1] = opacity;
333
- cTable[row * cWidth * 3 + column + 2] = opacity;
334
- }
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);
335
258
  }
336
- newColorTexture.resetFormatAndType();
337
- newColorTexture.create2DFromRaw(cWidth, 1, 3, VtkDataTypes.UNSIGNED_CHAR, cTable);
338
- }
339
- if (firstColorTransferFunc) {
340
- 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;
341
269
  }
342
- model.colorTexture = newColorTexture;
343
270
  } else {
344
271
  model.colorTexture = cTex.oglObject;
345
272
  }
346
- replaceGraphicsResource(model._openGLRenderWindow, model._colorTextureCore, firstColorTransferFunc);
347
- model._colorTextureCore = firstColorTransferFunc;
348
273
 
349
274
  // Build piecewise function buffer. This buffer is used either
350
275
  // for component weighting or opacity, depending on whether we're
351
276
  // rendering components independently or not.
352
- const opacityFunctions = [];
353
- for (let component = 0; component < numIComps; ++component) {
354
- opacityFunctions.push(firstActorProperty.getPiecewiseFunction(component));
355
- }
356
- const opacityFuncHash = getTransferFunctionsHash(opacityFunctions, iComps, numIComps);
357
- const firstPwFunc = firstActorProperty.getPiecewiseFunction();
358
- const pwfTex = model._openGLRenderWindow.getGraphicsResourceForObject(firstPwFunc);
359
- 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;
360
282
  if (reBuildPwf) {
361
283
  let pwfWidth = model.renderable.getOpacityTextureWidth();
362
284
  if (pwfWidth <= 0) {
@@ -364,13 +286,13 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
364
286
  }
365
287
  const pwfSize = pwfWidth * textureHeight;
366
288
  const pwfTable = new Uint8ClampedArray(pwfSize);
367
- const newOpacityTexture = vtkOpenGLTexture.newInstance();
368
- newOpacityTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
369
- if (firstPwFunc) {
289
+ model.pwfTexture = vtkOpenGLTexture.newInstance();
290
+ model.pwfTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
291
+ if (pwFunc) {
370
292
  const pwfFloatTable = new Float32Array(pwfSize);
371
293
  const tmpTable = new Float32Array(pwfWidth);
372
294
  for (let c = 0; c < numIComps; ++c) {
373
- const pwfun = firstActorProperty.getPiecewiseFunction(c);
295
+ const pwfun = ppty.getPiecewiseFunction(c);
374
296
  if (pwfun === null) {
375
297
  // Piecewise constant max if no function supplied for this component
376
298
  pwfFloatTable.fill(1.0);
@@ -385,28 +307,30 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
385
307
  }
386
308
  } else {
387
309
  for (let i = 0; i < pwfWidth; i++) {
388
- pwfFloatTable[i] = tmpTable[i];
310
+ pwfFloatTable[c * pwfWidth * 2 + i] = tmpTable[i];
389
311
  }
390
312
  }
391
313
  }
392
314
  }
393
- newOpacityTexture.resetFormatAndType();
394
- newOpacityTexture.create2DFromRaw(pwfWidth, textureHeight, 1, VtkDataTypes.FLOAT, pwfFloatTable);
315
+ model.pwfTexture.resetFormatAndType();
316
+ model.pwfTexture.create2DFromRaw(pwfWidth, textureHeight, 1, VtkDataTypes.FLOAT, pwfFloatTable);
395
317
  } else {
396
318
  // default is opaque
397
319
  pwfTable.fill(255.0);
398
- newOpacityTexture.resetFormatAndType();
399
- newOpacityTexture.create2DFromRaw(pwfWidth, textureHeight, 1, VtkDataTypes.UNSIGNED_CHAR, pwfTable);
400
- }
401
- if (firstPwFunc) {
402
- 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;
403
330
  }
404
- model.pwfTexture = newOpacityTexture;
405
331
  } else {
406
332
  model.pwfTexture = pwfTex.oglObject;
407
333
  }
408
- replaceGraphicsResource(model._openGLRenderWindow, model._pwfTextureCore, firstPwFunc);
409
- model._pwfTextureCore = firstPwFunc;
410
334
  const vboString = `${model.resliceGeom.getMTime()}A${model.renderable.getSlabThickness()}`;
411
335
  if (!model.tris.getCABO().getElementCount() || model.VBOBuildString !== vboString) {
412
336
  const points = vtkDataArray.newInstance({
@@ -467,12 +391,11 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
467
391
  };
468
392
  publicAPI.setMapperShaderParameters = (cellBO, ren, actor) => {
469
393
  const program = cellBO.getProgram();
470
- const firstImageData = model.currentValidInputs[0].imageData;
471
394
  if (cellBO.getCABO().getElementCount() && (model.VBOBuildTime.getMTime() > cellBO.getAttributeUpdateTime().getMTime() || cellBO.getShaderSourceTime().getMTime() > cellBO.getAttributeUpdateTime().getMTime())) {
472
395
  // Set the 3D texture
473
- model.scalarTextures.forEach((scalarTexture, component) => {
474
- program.setUniformi(`volumeTexture[${component}]`, scalarTexture.getTextureUnit());
475
- });
396
+ if (program.isUniformUsed('texture1')) {
397
+ program.setUniformi('texture1', model.openGLTexture.getTextureUnit());
398
+ }
476
399
 
477
400
  // Set the plane vertex attributes
478
401
  if (program.isAttributeUsed('vertexWC')) {
@@ -491,7 +414,7 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
491
414
  program.setUniformf('slabThickness', model.renderable.getSlabThickness());
492
415
  }
493
416
  if (program.isUniformUsed('spacing')) {
494
- program.setUniform3fv('spacing', firstImageData.getSpacing());
417
+ program.setUniform3fv('spacing', model.currentInput.getSpacing());
495
418
  }
496
419
  if (program.isUniformUsed('slabType')) {
497
420
  program.setUniformi('slabType', model.renderable.getSlabType());
@@ -507,8 +430,9 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
507
430
 
508
431
  // Set the world->texture matrix
509
432
  if (program.isUniformUsed('WCTCMatrix')) {
510
- const dim = firstImageData.getDimensions();
511
- mat4.copy(model.tmpMat4, firstImageData.getIndexToWorld());
433
+ const image = model.currentInput;
434
+ const dim = image.getDimensions();
435
+ mat4.copy(model.tmpMat4, image.getIndexToWorld());
512
436
  mat4.translate(model.tmpMat4, model.tmpMat4, [-0.5, -0.5, -0.5]);
513
437
  mat4.scale(model.tmpMat4, model.tmpMat4, dim);
514
438
  mat4.invert(model.tmpMat4, model.tmpMat4);
@@ -557,8 +481,8 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
557
481
  };
558
482
  publicAPI.setPropertyShaderParameters = (cellBO, ren, actor) => {
559
483
  const program = cellBO.getProgram();
560
- const firstPpty = actor.getProperty(model.currentValidInputs[0].inputIndex);
561
- const opacity = firstPpty.getOpacity();
484
+ const ppty = actor.getProperty();
485
+ const opacity = ppty.getOpacity();
562
486
  program.setUniformf('opacity', opacity);
563
487
 
564
488
  // Component mix
@@ -567,56 +491,53 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
567
491
  // - 2 comps => LA
568
492
  // - 3 comps => RGB + opacity from pwf
569
493
  // - 4 comps => RGBA
570
- const numComp = model.numberOfComponents;
571
- const iComps = firstPpty.getIndependentComponents();
494
+ const numComp = model.openGLTexture.getComponents();
495
+ const iComps = ppty.getIndependentComponents();
572
496
  if (iComps) {
573
497
  for (let i = 0; i < numComp; ++i) {
574
- program.setUniformf(`mix${i}`, firstPpty.getComponentWeight(i));
498
+ program.setUniformf(`mix${i}`, ppty.getComponentWeight(i));
575
499
  }
576
500
  }
577
501
 
502
+ // Color opacity map
503
+ const volInfo = model.openGLTexture.getVolumeInfo();
504
+
578
505
  // three levels of shift scale combined into one
579
506
  // for performance in the fragment shader
580
- for (let component = 0; component < numComp; component++) {
581
- const useMultiTexture = model.multiTexturePerVolumeEnabled;
582
- const textureIndex = useMultiTexture ? component : 0;
583
- const volInfoIndex = useMultiTexture ? 0 : component;
584
- const scalarTexture = model.scalarTextures[textureIndex];
585
- const volInfo = scalarTexture.getVolumeInfo();
586
- const volScale = volInfo.scale[volInfoIndex];
587
- const volOffset = volInfo.offset[volInfoIndex];
588
- const target = iComps ? component : 0;
589
-
590
- // color shift/scale
591
- let cw = firstPpty.getColorWindow();
592
- let cl = firstPpty.getColorLevel();
593
- const cfun = firstPpty.getRGBTransferFunction(target);
594
- 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()) {
595
513
  const cRange = cfun.getRange();
596
514
  cw = cRange[1] - cRange[0];
597
515
  cl = 0.5 * (cRange[1] + cRange[0]);
598
516
  }
599
- const colorScale = volScale / cw;
600
- const colorShift = (volOffset - cl) / cw + 0.5;
601
- program.setUniformf(`cshift${component}`, colorShift);
602
- 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);
603
524
 
604
- // pwf shift/scale
525
+ // pwf shift/scale
526
+ for (let i = 0; i < numComp; i++) {
605
527
  let pwfScale = 1.0;
606
528
  let pwfShift = 0.0;
607
- const pwfun = firstPpty.getPiecewiseFunction(target);
529
+ const target = iComps ? i : 0;
530
+ const pwfun = ppty.getPiecewiseFunction(target);
608
531
  if (pwfun) {
609
532
  const pwfRange = pwfun.getRange();
610
533
  const length = pwfRange[1] - pwfRange[0];
611
534
  const mid = 0.5 * (pwfRange[0] + pwfRange[1]);
612
- pwfScale = volScale / length;
613
- pwfShift = (volOffset - mid) / length + 0.5;
535
+ pwfScale = volInfo.scale[i] / length;
536
+ pwfShift = (volInfo.offset[i] - mid) / length + 0.5;
614
537
  }
615
- program.setUniformf(`pwfshift${component}`, pwfShift);
616
- program.setUniformf(`pwfscale${component}`, pwfScale);
538
+ program.setUniformf(`pwfshift${i}`, pwfShift);
539
+ program.setUniformf(`pwfscale${i}`, pwfScale);
617
540
  }
618
- const texColorUnit = model.colorTexture.getTextureUnit();
619
- program.setUniformi('colorTexture1', texColorUnit);
620
541
  const texOpacityUnit = model.pwfTexture.getTextureUnit();
621
542
  program.setUniformi('pwfTexture1', texOpacityUnit);
622
543
 
@@ -630,7 +551,8 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
630
551
  // input modified
631
552
  // light complexity changed
632
553
  // render pass shader replacement changed
633
- const iComp = actor.getProperty(model.currentValidInputs[0].inputIndex).getIndependentComponents();
554
+ const tNumComp = model.openGLTexture.getComponents();
555
+ const iComp = actor.getProperty().getIndependentComponents();
634
556
  const slabTh = model.renderable.getSlabThickness();
635
557
  const slabType = model.renderable.getSlabType();
636
558
  const slabTrap = model.renderable.getSlabTrapezoidIntegration();
@@ -640,10 +562,9 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
640
562
  if (!model.currentRenderPass && model.lastRenderPassShaderReplacement || model.currentRenderPass && model.currentRenderPass.getShaderReplacement() !== model.lastRenderPassShaderReplacement) {
641
563
  needRebuild = true;
642
564
  }
643
- 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) {
644
566
  model.lastHaveSeenDepthRequest = model.haveSeenDepthRequest;
645
- model.lastNumberOfComponents = model.numberOfComponents;
646
- model.lastMultiTexturePerVolumeEnabled = model.multiTexturePerVolumeEnabled;
567
+ model.lastTextureComponents = tNumComp;
647
568
  model.lastIndependentComponents = iComp;
648
569
  model.lastSlabThickness = slabTh;
649
570
  model.lastSlabType = slabType;
@@ -677,9 +598,9 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
677
598
  VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::TCoord::Dec', tcoordVSDec).result;
678
599
  const tcoordVSImpl = ['fragTexCoord = (WCTCMatrix * vertexWC).xyz;'];
679
600
  VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::TCoord::Impl', tcoordVSImpl).result;
680
- const tNumComp = model.numberOfComponents;
681
- const iComps = actor.getProperty(model.currentValidInputs[0].inputIndex).getIndependentComponents();
682
- 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;',
683
604
  // color shift and scale
684
605
  'uniform float cshift0;', 'uniform float cscale0;',
685
606
  // pwf shift and scale
@@ -690,18 +611,6 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
690
611
  'uniform float opacity;',
691
612
  // background color
692
613
  'uniform vec4 backgroundColor;'];
693
-
694
- // Function to sample texture
695
- tcoordFSDec.push('vec4 rawSampleTexture(vec3 pos) {');
696
- if (!model.multiTexturePerVolumeEnabled) {
697
- tcoordFSDec.push('return texture(volumeTexture[0], pos);', '}');
698
- } else {
699
- tcoordFSDec.push('vec4 rawSample;');
700
- for (let component = 0; component < model.scalarTextures.length; ++component) {
701
- tcoordFSDec.push(`rawSample[${component}] = texture(volumeTexture[${component}], pos)[0];`);
702
- }
703
- tcoordFSDec.push('return rawSample;', '}');
704
- }
705
614
  if (iComps) {
706
615
  for (let comp = 1; comp < tNumComp; comp++) {
707
616
  tcoordFSDec = tcoordFSDec.concat([
@@ -737,14 +646,14 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
737
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;', '}']);
738
647
  }
739
648
  FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::TCoord::Dec', tcoordFSDec).result;
740
- 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);'];
741
650
  if (slabThickness > 0.0) {
742
- 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);', '}']);
743
652
  }
744
653
  if (iComps) {
745
654
  const rgba = ['r', 'g', 'b', 'a'];
746
655
  for (let comp = 0; comp < tNumComp; ++comp) {
747
- 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;`]);
748
657
  }
749
658
  switch (tNumComp) {
750
659
  case 1:
@@ -830,8 +739,8 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
830
739
  }
831
740
  publicAPI.updateResliceGeometry = () => {
832
741
  let resGeomString = '';
833
- const firstImageData = model.currentValidInputs[0].imageData;
834
- const imageBounds = firstImageData?.getBounds();
742
+ const image = model.currentInput;
743
+ const imageBounds = image?.getBounds();
835
744
  // Orthogonal slicing by default
836
745
  let orthoSlicing = true;
837
746
  let orthoAxis = 2;
@@ -843,11 +752,11 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
843
752
  resGeomString = resGeomString.concat(`Plane${slicePlane.getMTime()}`);
844
753
  // Compute a world-to-image-orientation matrix.
845
754
  const w2io = mat3.create();
846
- if (firstImageData) {
847
- resGeomString = resGeomString.concat(`Image${firstImageData.getMTime()}`);
755
+ if (image) {
756
+ resGeomString = resGeomString.concat(`Image${image.getMTime()}`);
848
757
  // Ignore the translation component since we are
849
758
  // using it on vectors rather than positions.
850
- mat3.set(w2io, ...firstImageData.getDirection());
759
+ mat3.set(w2io, ...image.getDirection());
851
760
  mat3.invert(w2io, w2io);
852
761
  }
853
762
  // Check to see if we can bypass oblique slicing related bounds computation
@@ -860,14 +769,14 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
860
769
  const plane = vtkPlane.newInstance();
861
770
  plane.setNormal(0, 0, 1);
862
771
  let bds = [0, 1, 0, 1, 0, 1];
863
- if (firstImageData) {
772
+ if (image) {
864
773
  bds = imageBounds;
865
774
  }
866
775
  plane.setOrigin(bds[0], bds[2], 0.5 * (bds[5] + bds[4]));
867
776
  model.renderable.setSlicePlane(plane);
868
777
  resGeomString = resGeomString.concat(`Plane${slicePlane?.getMTime()}`);
869
- if (firstImageData) {
870
- resGeomString = resGeomString.concat(`Image${firstImageData.getMTime()}`);
778
+ if (image) {
779
+ resGeomString = resGeomString.concat(`Image${image.getMTime()}`);
871
780
  }
872
781
  }
873
782
  if (!model.resliceGeom || model.resliceGeomUpdateString !== resGeomString) {
@@ -880,7 +789,7 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
880
789
  model.resliceGeom.getPointData().setNormals(slicePD.getPointData().getNormals());
881
790
  } else if (slicePlane) {
882
791
  if (!orthoSlicing) {
883
- model.outlineFilter.setInputData(firstImageData);
792
+ model.outlineFilter.setInputData(image);
884
793
  model.cutter.setInputConnection(model.outlineFilter.getOutputPort());
885
794
  model.cutter.setCutFunction(slicePlane);
886
795
  model.lineToSurfaceFilter.setInputConnection(model.cutter.getOutputPort());
@@ -913,9 +822,9 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
913
822
  // Since the image-local normal is axis-aligned, we
914
823
  // can quickly construct the cutting plane using indexToWorld transforms.
915
824
  const ptsArray = new Float32Array(12);
916
- const indexSpacePlaneOrigin = firstImageData.worldToIndex(slicePlane.getOrigin(), [0, 0, 0]);
825
+ const indexSpacePlaneOrigin = image.worldToIndex(slicePlane.getOrigin(), [0, 0, 0]);
917
826
  const otherAxes = [(orthoAxis + 1) % 3, (orthoAxis + 2) % 3].sort();
918
- const ext = firstImageData.getSpatialExtent();
827
+ const ext = image.getSpatialExtent();
919
828
  let ptIdx = 0;
920
829
  for (let i = 0; i < 2; ++i) {
921
830
  for (let j = 0; j < 2; ++j) {
@@ -925,7 +834,7 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
925
834
  ptIdx += 3;
926
835
  }
927
836
  }
928
- model.transform.setMatrix(firstImageData.getIndexToWorld());
837
+ model.transform.setMatrix(image.getIndexToWorld());
929
838
  model.transform.transformPoints(ptsArray, ptsArray);
930
839
  const cellArray = new Uint16Array(8);
931
840
  cellArray[0] = 3;
@@ -963,9 +872,11 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
963
872
  model.resliceGeom?.modified();
964
873
  }
965
874
  };
966
- publicAPI.setScalarTextures = scalarTextures => {
967
- model.scalarTextures = [...scalarTextures];
968
- model._externalOpenGLTexture = true;
875
+ publicAPI.setOpenGLTexture = oglTex => {
876
+ if (oglTex) {
877
+ model.openGLTexture = oglTex;
878
+ model._externalOpenGLTexture = true;
879
+ }
969
880
  };
970
881
  publicAPI.delete = chain(() => {
971
882
  if (model._openGLRenderWindow) {
@@ -984,21 +895,22 @@ const DEFAULT_VALUES = {
984
895
  haveSeenDepthRequest: false,
985
896
  lastHaveSeenDepthRequest: false,
986
897
  lastIndependentComponents: false,
987
- lastNumberOfComponents: 0,
988
- lastMultiTexturePerVolumeEnabled: false,
898
+ lastTextureComponents: 0,
989
899
  lastSlabThickness: 0,
990
900
  lastSlabTrapezoidIntegration: 0,
991
901
  lastSlabType: -1,
992
- scalarTextures: [],
993
- _scalarTexturesCore: [],
994
- colorTexture: null,
995
- _colorTextureCore: null,
996
- pwfTexture: null,
997
- _pwfTextureCore: null,
998
- _externalOpenGLTexture: false,
902
+ openGLTexture: null,
903
+ colorTextureString: null,
904
+ pwfTextureString: null,
999
905
  resliceGeom: null,
1000
906
  resliceGeomUpdateString: null,
1001
- tris: null
907
+ tris: null,
908
+ colorTexture: null,
909
+ pwfTexture: null,
910
+ _externalOpenGLTexture: false
911
+ // _scalars: null,
912
+ // _colorTransferFunc: null,
913
+ // _pwFunc: null,
1002
914
  };
1003
915
 
1004
916
  // ----------------------------------------------------------------------------
@@ -1012,7 +924,7 @@ function extend(publicAPI, model) {
1012
924
  vtkReplacementShaderMapper.implementReplaceShaderCoincidentOffset(publicAPI, model, initialValues);
1013
925
  vtkReplacementShaderMapper.implementBuildShadersWithReplacements(publicAPI, model, initialValues);
1014
926
  model.tris = vtkHelper.newInstance();
1015
- model.scalarTextures = [];
927
+ model.openGLTexture = null;
1016
928
  model.colorTexture = null;
1017
929
  model.pwfTexture = null;
1018
930
  model.VBOBuildTime = {};
@@ -1027,7 +939,7 @@ function extend(publicAPI, model) {
1027
939
  model.cutter = vtkCutter.newInstance();
1028
940
  model.lineToSurfaceFilter = vtkClosedPolyLineToSurfaceFilter.newInstance();
1029
941
  model.transform = vtkTransform.newInstance();
1030
- get(publicAPI, model, ['scalarTextures']);
942
+ get(publicAPI, model, ['openGLTexture']);
1031
943
 
1032
944
  // Object methods
1033
945
  vtkOpenGLImageResliceMapper(publicAPI, model);