@kitware/vtk.js 32.5.1 → 33.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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, getTransferFunctionHash } from './RenderWindow/resourceSharingHelper.js';
16
+ import { getImageDataHash, getTransferFunctionsHash } 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,8 +49,43 @@ 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
+ }
52
86
  function unregisterGraphicsResources(renderWindow) {
53
- [model._scalars, model._colorTransferFunc, model._pwFunc].forEach(coreObject => renderWindow.unregisterGraphicsResourceUser(coreObject, publicAPI));
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));
54
89
  }
55
90
  publicAPI.buildPass = prepass => {
56
91
  if (prepass) {
@@ -110,11 +145,28 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
110
145
  type: 'StartEvent'
111
146
  });
112
147
  model.renderable.update();
113
- model.currentInput = model.renderable.getInputData();
114
- if (!model.currentInput) {
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) {
115
161
  vtkErrorMacro('No input!');
116
162
  return;
117
163
  }
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();
118
170
  publicAPI.updateResliceGeometry();
119
171
  publicAPI.renderPieceStart(ren, actor);
120
172
  publicAPI.renderPieceDraw(ren, actor);
@@ -126,17 +178,35 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
126
178
  publicAPI.renderPieceStart = (ren, actor) => {
127
179
  // make sure the BOs are up to date
128
180
  publicAPI.updateBufferObjects(ren, actor);
129
- const iType = actor.getProperty().getInterpolationType();
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();
130
204
  if (iType === InterpolationType.NEAREST) {
131
- model.openGLTexture.setMinificationFilter(Filter.NEAREST);
132
- model.openGLTexture.setMagnificationFilter(Filter.NEAREST);
133
205
  model.colorTexture.setMinificationFilter(Filter.NEAREST);
134
206
  model.colorTexture.setMagnificationFilter(Filter.NEAREST);
135
207
  model.pwfTexture.setMinificationFilter(Filter.NEAREST);
136
208
  model.pwfTexture.setMagnificationFilter(Filter.NEAREST);
137
209
  } else {
138
- model.openGLTexture.setMinificationFilter(Filter.LINEAR);
139
- model.openGLTexture.setMagnificationFilter(Filter.LINEAR);
140
210
  model.colorTexture.setMinificationFilter(Filter.LINEAR);
141
211
  model.colorTexture.setMagnificationFilter(Filter.LINEAR);
142
212
  model.pwfTexture.setMinificationFilter(Filter.LINEAR);
@@ -150,9 +220,8 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
150
220
  const gl = model.context;
151
221
 
152
222
  // render the texture
153
- model.openGLTexture.activate();
154
- model.colorTexture.activate();
155
- model.pwfTexture.activate();
223
+ const allTextures = [...model.scalarTextures, model.colorTexture, model.pwfTexture];
224
+ allTextures.forEach(texture => texture.activate());
156
225
 
157
226
  // update shaders if required
158
227
  publicAPI.updateShaders(model.tris, ren, actor);
@@ -160,9 +229,7 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
160
229
  // Finally draw
161
230
  gl.drawArrays(gl.TRIANGLES, 0, model.tris.getCABO().getElementCount());
162
231
  model.tris.getVAO().release();
163
- model.openGLTexture.deactivate();
164
- model.colorTexture.deactivate();
165
- model.pwfTexture.deactivate();
232
+ allTextures.forEach(texture => texture.deactivate());
166
233
  };
167
234
  publicAPI.renderPieceFinish = (ren, actor) => {};
168
235
  publicAPI.updateBufferObjects = (ren, actor) => {
@@ -171,56 +238,63 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
171
238
  publicAPI.buildBufferObjects(ren, actor);
172
239
  }
173
240
  };
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();
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();
175
247
  publicAPI.buildBufferObjects = (ren, actor) => {
176
- const image = model.currentInput;
177
- if (!image) {
178
- return;
179
- }
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
- if (reBuildTex) {
189
- model.openGLTexture = vtkOpenGLTexture.newInstance();
190
- model.openGLTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
191
- // Build the image scalar texture
192
- const dims = image.getDimensions();
193
- // Use norm16 for the 3D texture if the extension is available
194
- model.openGLTexture.setOglNorm16Ext(model.context.getExtension('EXT_texture_norm16'));
195
- model.openGLTexture.resetFormatAndType();
196
- model.openGLTexture.create3DFilterableFromDataArray(dims[0], dims[1], dims[2], scalars);
197
- model._openGLRenderWindow.setGraphicsResourceForObject(scalars, model.openGLTexture, toString);
198
- if (scalars !== model._scalars) {
199
- model._openGLRenderWindow.registerGraphicsResourceUser(scalars, publicAPI);
200
- model._openGLRenderWindow.unregisterGraphicsResourceUser(model._scalars, publicAPI);
201
- }
202
- model._scalars = scalars;
203
- } else {
204
- model.openGLTexture = tex.oglObject;
205
- }
206
- const ppty = actor.getProperty();
207
- const iComps = ppty.getIndependentComponents();
208
- const numIComps = iComps ? numComp : 1;
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;
209
279
  const textureHeight = iComps ? 2 * numIComps : 1;
210
- const colorTransferFunc = ppty.getRGBTransferFunction();
211
- toString = getTransferFunctionHash(colorTransferFunc, iComps, numIComps);
212
- const cTex = model._openGLRenderWindow.getGraphicsResourceForObject(colorTransferFunc);
213
- const reBuildC = !cTex?.oglObject?.getHandle() || cTex?.hash !== toString;
280
+ const colorTransferFunctions = [];
281
+ for (let component = 0; component < numIComps; ++component) {
282
+ colorTransferFunctions.push(firstActorProperty.getRGBTransferFunction(component));
283
+ }
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;
214
288
  if (reBuildC) {
215
289
  const cWidth = 1024;
216
290
  const cSize = cWidth * textureHeight * 3;
217
291
  const cTable = new Uint8ClampedArray(cSize);
218
- model.colorTexture = vtkOpenGLTexture.newInstance();
219
- model.colorTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
220
- if (colorTransferFunc) {
292
+ const newColorTexture = vtkOpenGLTexture.newInstance();
293
+ newColorTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
294
+ if (firstColorTransferFunc) {
221
295
  const tmpTable = new Float32Array(cWidth * 3);
222
296
  for (let c = 0; c < numIComps; c++) {
223
- const cfun = ppty.getRGBTransferFunction(c);
297
+ const cfun = firstActorProperty.getRGBTransferFunction(c);
224
298
  const cRange = cfun.getRange();
225
299
  cfun.getTable(cRange[0], cRange[1], cWidth, tmpTable, 1);
226
300
  if (iComps) {
@@ -230,52 +304,57 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
230
304
  }
231
305
  } else {
232
306
  for (let i = 0; i < cWidth * 3; i++) {
233
- cTable[c * cWidth * 6 + i] = 255.0 * tmpTable[i];
307
+ cTable[c * cWidth * 3 + i] = 255.0 * tmpTable[i];
234
308
  }
235
309
  }
236
310
  }
237
- model.colorTexture.resetFormatAndType();
238
- model.colorTexture.create2DFromRaw(cWidth, textureHeight, 3, VtkDataTypes.UNSIGNED_CHAR, cTable);
311
+ newColorTexture.resetFormatAndType();
312
+ newColorTexture.create2DFromRaw(cWidth, textureHeight, 3, VtkDataTypes.UNSIGNED_CHAR, cTable);
239
313
  } else {
240
- for (let i = 0; i < cWidth * 3; ++i) {
241
- cTable[i] = 255.0 * i / ((cWidth - 1) * 3);
242
- cTable[i + 1] = 255.0 * i / ((cWidth - 1) * 3);
243
- cTable[i + 2] = 255.0 * i / ((cWidth - 1) * 3);
244
- }
245
- model.colorTexture.resetFormatAndType();
246
- model.colorTexture.create2DFromRaw(cWidth, 1, 3, VtkDataTypes.UNSIGNED_CHAR, cTable);
247
- }
248
- if (colorTransferFunc) {
249
- model._openGLRenderWindow.setGraphicsResourceForObject(colorTransferFunc, model.colorTexture, toString);
250
- if (colorTransferFunc !== model._colorTransferFunc) {
251
- model._openGLRenderWindow.registerGraphicsResourceUser(colorTransferFunc, publicAPI);
252
- model._openGLRenderWindow.unregisterGraphicsResourceUser(model._colorTransferFunc, publicAPI);
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
+ }
253
322
  }
254
- model._colorTransferFunc = colorTransferFunc;
323
+ newColorTexture.resetFormatAndType();
324
+ newColorTexture.create2DFromRaw(cWidth, 1, 3, VtkDataTypes.UNSIGNED_CHAR, cTable);
325
+ }
326
+ if (firstColorTransferFunc) {
327
+ model._openGLRenderWindow.setGraphicsResourceForObject(firstColorTransferFunc, newColorTexture, colorFuncHash);
255
328
  }
329
+ model.colorTexture = newColorTexture;
256
330
  } else {
257
331
  model.colorTexture = cTex.oglObject;
258
332
  }
333
+ replaceGraphicsResource(model._openGLRenderWindow, model._colorTextureCore, firstColorTransferFunc);
334
+ model._colorTextureCore = firstColorTransferFunc;
259
335
 
260
336
  // Build piecewise function buffer. This buffer is used either
261
337
  // for component weighting or opacity, depending on whether we're
262
338
  // rendering components independently or not.
263
- const pwFunc = ppty.getPiecewiseFunction();
264
- toString = getTransferFunctionHash(pwFunc, iComps, numIComps);
265
- const pwfTex = model._openGLRenderWindow.getGraphicsResourceForObject(pwFunc);
266
- // rebuild opacity tfun?
267
- const reBuildPwf = !pwfTex?.oglObject?.getHandle() || pwfTex?.hash !== toString;
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;
268
347
  if (reBuildPwf) {
269
348
  const pwfWidth = 1024;
270
349
  const pwfSize = pwfWidth * textureHeight;
271
350
  const pwfTable = new Uint8ClampedArray(pwfSize);
272
- model.pwfTexture = vtkOpenGLTexture.newInstance();
273
- model.pwfTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
274
- if (pwFunc) {
351
+ const newOpacityTexture = vtkOpenGLTexture.newInstance();
352
+ newOpacityTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
353
+ if (firstPwFunc) {
275
354
  const pwfFloatTable = new Float32Array(pwfSize);
276
355
  const tmpTable = new Float32Array(pwfWidth);
277
356
  for (let c = 0; c < numIComps; ++c) {
278
- const pwfun = ppty.getPiecewiseFunction(c);
357
+ const pwfun = firstActorProperty.getPiecewiseFunction(c);
279
358
  if (pwfun === null) {
280
359
  // Piecewise constant max if no function supplied for this component
281
360
  pwfFloatTable.fill(1.0);
@@ -290,30 +369,28 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
290
369
  }
291
370
  } else {
292
371
  for (let i = 0; i < pwfWidth; i++) {
293
- pwfFloatTable[c * pwfWidth * 2 + i] = tmpTable[i];
372
+ pwfFloatTable[i] = tmpTable[i];
294
373
  }
295
374
  }
296
375
  }
297
376
  }
298
- model.pwfTexture.resetFormatAndType();
299
- model.pwfTexture.create2DFromRaw(pwfWidth, textureHeight, 1, VtkDataTypes.FLOAT, pwfFloatTable);
377
+ newOpacityTexture.resetFormatAndType();
378
+ newOpacityTexture.create2DFromRaw(pwfWidth, textureHeight, 1, VtkDataTypes.FLOAT, pwfFloatTable);
300
379
  } else {
301
380
  // default is opaque
302
381
  pwfTable.fill(255.0);
303
- model.pwfTexture.resetFormatAndType();
304
- model.pwfTexture.create2DFromRaw(pwfWidth, 1, 1, VtkDataTypes.UNSIGNED_CHAR, pwfTable);
305
- }
306
- if (pwFunc) {
307
- model._openGLRenderWindow.setGraphicsResourceForObject(pwFunc, model.pwfTexture, toString);
308
- if (pwFunc !== model._pwFunc) {
309
- model._openGLRenderWindow.registerGraphicsResourceUser(pwFunc, publicAPI);
310
- model._openGLRenderWindow.unregisterGraphicsResourceUser(model._pwFunc, publicAPI);
311
- }
312
- model._pwFunc = pwFunc;
382
+ newOpacityTexture.resetFormatAndType();
383
+ newOpacityTexture.create2DFromRaw(pwfWidth, textureHeight, 1, VtkDataTypes.UNSIGNED_CHAR, pwfTable);
313
384
  }
385
+ if (firstPwFunc) {
386
+ model._openGLRenderWindow.setGraphicsResourceForObject(firstPwFunc, newOpacityTexture, opacityFuncHash);
387
+ }
388
+ model.pwfTexture = newOpacityTexture;
314
389
  } else {
315
390
  model.pwfTexture = pwfTex.oglObject;
316
391
  }
392
+ replaceGraphicsResource(model._openGLRenderWindow, model._pwfTextureCore, firstPwFunc);
393
+ model._pwfTextureCore = firstPwFunc;
317
394
  const vboString = `${model.resliceGeom.getMTime()}A${model.renderable.getSlabThickness()}`;
318
395
  if (!model.tris.getCABO().getElementCount() || model.VBOBuildString !== vboString) {
319
396
  const points = vtkDataArray.newInstance({
@@ -374,11 +451,12 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
374
451
  };
375
452
  publicAPI.setMapperShaderParameters = (cellBO, ren, actor) => {
376
453
  const program = cellBO.getProgram();
454
+ const firstImageData = model.currentValidInputs[0].imageData;
377
455
  if (cellBO.getCABO().getElementCount() && (model.VBOBuildTime.getMTime() > cellBO.getAttributeUpdateTime().getMTime() || cellBO.getShaderSourceTime().getMTime() > cellBO.getAttributeUpdateTime().getMTime())) {
378
456
  // Set the 3D texture
379
- if (program.isUniformUsed('texture1')) {
380
- program.setUniformi('texture1', model.openGLTexture.getTextureUnit());
381
- }
457
+ model.scalarTextures.forEach((scalarTexture, component) => {
458
+ program.setUniformi(`volumeTexture[${component}]`, scalarTexture.getTextureUnit());
459
+ });
382
460
 
383
461
  // Set the plane vertex attributes
384
462
  if (program.isAttributeUsed('vertexWC')) {
@@ -397,7 +475,7 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
397
475
  program.setUniformf('slabThickness', model.renderable.getSlabThickness());
398
476
  }
399
477
  if (program.isUniformUsed('spacing')) {
400
- program.setUniform3fv('spacing', model.currentInput.getSpacing());
478
+ program.setUniform3fv('spacing', firstImageData.getSpacing());
401
479
  }
402
480
  if (program.isUniformUsed('slabType')) {
403
481
  program.setUniformi('slabType', model.renderable.getSlabType());
@@ -413,9 +491,8 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
413
491
 
414
492
  // Set the world->texture matrix
415
493
  if (program.isUniformUsed('WCTCMatrix')) {
416
- const image = model.currentInput;
417
- const dim = image.getDimensions();
418
- mat4.copy(model.tmpMat4, image.getIndexToWorld());
494
+ const dim = firstImageData.getDimensions();
495
+ mat4.copy(model.tmpMat4, firstImageData.getIndexToWorld());
419
496
  mat4.translate(model.tmpMat4, model.tmpMat4, [-0.5, -0.5, -0.5]);
420
497
  mat4.scale(model.tmpMat4, model.tmpMat4, dim);
421
498
  mat4.invert(model.tmpMat4, model.tmpMat4);
@@ -464,8 +541,8 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
464
541
  };
465
542
  publicAPI.setPropertyShaderParameters = (cellBO, ren, actor) => {
466
543
  const program = cellBO.getProgram();
467
- const ppty = actor.getProperty();
468
- const opacity = ppty.getOpacity();
544
+ const firstPpty = actor.getProperty(model.currentValidInputs[0].inputIndex);
545
+ const opacity = firstPpty.getOpacity();
469
546
  program.setUniformf('opacity', opacity);
470
547
 
471
548
  // Component mix
@@ -474,53 +551,56 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
474
551
  // - 2 comps => LA
475
552
  // - 3 comps => RGB + opacity from pwf
476
553
  // - 4 comps => RGBA
477
- const numComp = model.openGLTexture.getComponents();
478
- const iComps = ppty.getIndependentComponents();
554
+ const numComp = model.numberOfComponents;
555
+ const iComps = firstPpty.getIndependentComponents();
479
556
  if (iComps) {
480
557
  for (let i = 0; i < numComp; ++i) {
481
- program.setUniformf(`mix${i}`, ppty.getComponentWeight(i));
558
+ program.setUniformf(`mix${i}`, firstPpty.getComponentWeight(i));
482
559
  }
483
560
  }
484
561
 
485
- // Color opacity map
486
- const volInfo = model.openGLTexture.getVolumeInfo();
487
-
488
562
  // three levels of shift scale combined into one
489
563
  // for performance in the fragment shader
490
- for (let i = 0; i < numComp; i++) {
491
- let cw = ppty.getColorWindow();
492
- let cl = ppty.getColorLevel();
493
- const target = iComps ? i : 0;
494
- const cfun = ppty.getRGBTransferFunction(target);
495
- if (cfun && ppty.getUseLookupTableScalarRange()) {
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()) {
496
579
  const cRange = cfun.getRange();
497
580
  cw = cRange[1] - cRange[0];
498
581
  cl = 0.5 * (cRange[1] + cRange[0]);
499
582
  }
500
- const scale = volInfo.scale[i] / cw;
501
- const shift = (volInfo.offset[i] - cl) / cw + 0.5;
502
- program.setUniformf(`cshift${i}`, shift);
503
- program.setUniformf(`cscale${i}`, scale);
504
- }
505
- const texColorUnit = model.colorTexture.getTextureUnit();
506
- program.setUniformi('colorTexture1', texColorUnit);
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);
507
587
 
508
- // pwf shift/scale
509
- for (let i = 0; i < numComp; i++) {
588
+ // pwf shift/scale
510
589
  let pwfScale = 1.0;
511
590
  let pwfShift = 0.0;
512
- const target = iComps ? i : 0;
513
- const pwfun = ppty.getPiecewiseFunction(target);
591
+ const pwfun = firstPpty.getPiecewiseFunction(target);
514
592
  if (pwfun) {
515
593
  const pwfRange = pwfun.getRange();
516
594
  const length = pwfRange[1] - pwfRange[0];
517
595
  const mid = 0.5 * (pwfRange[0] + pwfRange[1]);
518
- pwfScale = volInfo.scale[i] / length;
519
- pwfShift = (volInfo.offset[i] - mid) / length + 0.5;
596
+ pwfScale = volScale / length;
597
+ pwfShift = (volOffset - mid) / length + 0.5;
520
598
  }
521
- program.setUniformf(`pwfshift${i}`, pwfShift);
522
- program.setUniformf(`pwfscale${i}`, pwfScale);
599
+ program.setUniformf(`pwfshift${component}`, pwfShift);
600
+ program.setUniformf(`pwfscale${component}`, pwfScale);
523
601
  }
602
+ const texColorUnit = model.colorTexture.getTextureUnit();
603
+ program.setUniformi('colorTexture1', texColorUnit);
524
604
  const texOpacityUnit = model.pwfTexture.getTextureUnit();
525
605
  program.setUniformi('pwfTexture1', texOpacityUnit);
526
606
 
@@ -534,8 +614,7 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
534
614
  // input modified
535
615
  // light complexity changed
536
616
  // render pass shader replacement changed
537
- const tNumComp = model.openGLTexture.getComponents();
538
- const iComp = actor.getProperty().getIndependentComponents();
617
+ const iComp = actor.getProperty(model.currentValidInputs[0].inputIndex).getIndependentComponents();
539
618
  const slabTh = model.renderable.getSlabThickness();
540
619
  const slabType = model.renderable.getSlabType();
541
620
  const slabTrap = model.renderable.getSlabTrapezoidIntegration();
@@ -545,9 +624,10 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
545
624
  if (!model.currentRenderPass && model.lastRenderPassShaderReplacement || model.currentRenderPass && model.currentRenderPass.getShaderReplacement() !== model.lastRenderPassShaderReplacement) {
546
625
  needRebuild = true;
547
626
  }
548
- 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) {
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) {
549
628
  model.lastHaveSeenDepthRequest = model.haveSeenDepthRequest;
550
- model.lastTextureComponents = tNumComp;
629
+ model.lastNumberOfComponents = model.numberOfComponents;
630
+ model.lastMultiTexturePerVolumeEnabled = model.multiTexturePerVolumeEnabled;
551
631
  model.lastIndependentComponents = iComp;
552
632
  model.lastSlabThickness = slabTh;
553
633
  model.lastSlabType = slabType;
@@ -581,9 +661,9 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
581
661
  VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::TCoord::Dec', tcoordVSDec).result;
582
662
  const tcoordVSImpl = ['fragTexCoord = (WCTCMatrix * vertexWC).xyz;'];
583
663
  VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::TCoord::Impl', tcoordVSImpl).result;
584
- const tNumComp = model.openGLTexture.getComponents();
585
- const iComps = actor.getProperty().getIndependentComponents();
586
- let tcoordFSDec = ['in vec3 fragTexCoord;', 'uniform highp sampler3D texture1;', 'uniform mat4 WCTCMatrix;',
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;',
587
667
  // color shift and scale
588
668
  'uniform float cshift0;', 'uniform float cscale0;',
589
669
  // pwf shift and scale
@@ -594,6 +674,18 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
594
674
  'uniform float opacity;',
595
675
  // background color
596
676
  '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
+ }
597
689
  if (iComps) {
598
690
  for (let comp = 1; comp < tNumComp; comp++) {
599
691
  tcoordFSDec = tcoordFSDec.concat([
@@ -629,14 +721,14 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
629
721
  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;', '}']);
630
722
  }
631
723
  FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::TCoord::Dec', tcoordFSDec).result;
632
- 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);'];
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);'];
633
725
  if (slabThickness > 0.0) {
634
- 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);', '}']);
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);', '}']);
635
727
  }
636
728
  if (iComps) {
637
729
  const rgba = ['r', 'g', 'b', 'a'];
638
730
  for (let comp = 0; comp < tNumComp; ++comp) {
639
- 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;`]);
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;`]);
640
732
  }
641
733
  switch (tNumComp) {
642
734
  case 1:
@@ -722,8 +814,8 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
722
814
  }
723
815
  publicAPI.updateResliceGeometry = () => {
724
816
  let resGeomString = '';
725
- const image = model.currentInput;
726
- const imageBounds = image?.getBounds();
817
+ const firstImageData = model.currentValidInputs[0].imageData;
818
+ const imageBounds = firstImageData?.getBounds();
727
819
  // Orthogonal slicing by default
728
820
  let orthoSlicing = true;
729
821
  let orthoAxis = 2;
@@ -735,11 +827,11 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
735
827
  resGeomString = resGeomString.concat(`Plane${slicePlane.getMTime()}`);
736
828
  // Compute a world-to-image-orientation matrix.
737
829
  const w2io = mat3.create();
738
- if (image) {
739
- resGeomString = resGeomString.concat(`Image${image.getMTime()}`);
830
+ if (firstImageData) {
831
+ resGeomString = resGeomString.concat(`Image${firstImageData.getMTime()}`);
740
832
  // Ignore the translation component since we are
741
833
  // using it on vectors rather than positions.
742
- mat3.set(w2io, ...image.getDirection());
834
+ mat3.set(w2io, ...firstImageData.getDirection());
743
835
  mat3.invert(w2io, w2io);
744
836
  }
745
837
  // Check to see if we can bypass oblique slicing related bounds computation
@@ -752,14 +844,14 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
752
844
  const plane = vtkPlane.newInstance();
753
845
  plane.setNormal(0, 0, 1);
754
846
  let bds = [0, 1, 0, 1, 0, 1];
755
- if (image) {
847
+ if (firstImageData) {
756
848
  bds = imageBounds;
757
849
  }
758
850
  plane.setOrigin(bds[0], bds[2], 0.5 * (bds[5] + bds[4]));
759
851
  model.renderable.setSlicePlane(plane);
760
852
  resGeomString = resGeomString.concat(`Plane${slicePlane?.getMTime()}`);
761
- if (image) {
762
- resGeomString = resGeomString.concat(`Image${image.getMTime()}`);
853
+ if (firstImageData) {
854
+ resGeomString = resGeomString.concat(`Image${firstImageData.getMTime()}`);
763
855
  }
764
856
  }
765
857
  if (!model.resliceGeom || model.resliceGeomUpdateString !== resGeomString) {
@@ -772,7 +864,7 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
772
864
  model.resliceGeom.getPointData().setNormals(slicePD.getPointData().getNormals());
773
865
  } else if (slicePlane) {
774
866
  if (!orthoSlicing) {
775
- model.outlineFilter.setInputData(image);
867
+ model.outlineFilter.setInputData(firstImageData);
776
868
  model.cutter.setInputConnection(model.outlineFilter.getOutputPort());
777
869
  model.cutter.setCutFunction(slicePlane);
778
870
  model.lineToSurfaceFilter.setInputConnection(model.cutter.getOutputPort());
@@ -805,9 +897,9 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
805
897
  // Since the image-local normal is axis-aligned, we
806
898
  // can quickly construct the cutting plane using indexToWorld transforms.
807
899
  const ptsArray = new Float32Array(12);
808
- const indexSpacePlaneOrigin = image.worldToIndex(slicePlane.getOrigin(), [0, 0, 0]);
900
+ const indexSpacePlaneOrigin = firstImageData.worldToIndex(slicePlane.getOrigin(), [0, 0, 0]);
809
901
  const otherAxes = [(orthoAxis + 1) % 3, (orthoAxis + 2) % 3].sort();
810
- const ext = image.getSpatialExtent();
902
+ const ext = firstImageData.getSpatialExtent();
811
903
  let ptIdx = 0;
812
904
  for (let i = 0; i < 2; ++i) {
813
905
  for (let j = 0; j < 2; ++j) {
@@ -817,7 +909,7 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
817
909
  ptIdx += 3;
818
910
  }
819
911
  }
820
- model.transform.setMatrix(image.getIndexToWorld());
912
+ model.transform.setMatrix(firstImageData.getIndexToWorld());
821
913
  model.transform.transformPoints(ptsArray, ptsArray);
822
914
  const cellArray = new Uint16Array(8);
823
915
  cellArray[0] = 3;
@@ -855,11 +947,9 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
855
947
  model.resliceGeom?.modified();
856
948
  }
857
949
  };
858
- publicAPI.setOpenGLTexture = oglTex => {
859
- if (oglTex) {
860
- model.openGLTexture = oglTex;
861
- model._externalOpenGLTexture = true;
862
- }
950
+ publicAPI.setScalarTextures = scalarTextures => {
951
+ model.scalarTextures = [...scalarTextures];
952
+ model._externalOpenGLTexture = true;
863
953
  };
864
954
  publicAPI.delete = chain(() => {
865
955
  if (model._openGLRenderWindow) {
@@ -878,22 +968,21 @@ const DEFAULT_VALUES = {
878
968
  haveSeenDepthRequest: false,
879
969
  lastHaveSeenDepthRequest: false,
880
970
  lastIndependentComponents: false,
881
- lastTextureComponents: 0,
971
+ lastNumberOfComponents: 0,
972
+ lastMultiTexturePerVolumeEnabled: false,
882
973
  lastSlabThickness: 0,
883
974
  lastSlabTrapezoidIntegration: 0,
884
975
  lastSlabType: -1,
885
- openGLTexture: null,
886
- colorTextureString: null,
887
- pwfTextureString: null,
888
- resliceGeom: null,
889
- resliceGeomUpdateString: null,
890
- tris: null,
976
+ scalarTextures: [],
977
+ _scalarTexturesCore: [],
891
978
  colorTexture: null,
979
+ _colorTextureCore: null,
892
980
  pwfTexture: null,
893
- _externalOpenGLTexture: false
894
- // _scalars: null,
895
- // _colorTransferFunc: null,
896
- // _pwFunc: null,
981
+ _pwfTextureCore: null,
982
+ _externalOpenGLTexture: false,
983
+ resliceGeom: null,
984
+ resliceGeomUpdateString: null,
985
+ tris: null
897
986
  };
898
987
 
899
988
  // ----------------------------------------------------------------------------
@@ -907,7 +996,7 @@ function extend(publicAPI, model) {
907
996
  vtkReplacementShaderMapper.implementReplaceShaderCoincidentOffset(publicAPI, model, initialValues);
908
997
  vtkReplacementShaderMapper.implementBuildShadersWithReplacements(publicAPI, model, initialValues);
909
998
  model.tris = vtkHelper.newInstance();
910
- model.openGLTexture = null;
999
+ model.scalarTextures = [];
911
1000
  model.colorTexture = null;
912
1001
  model.pwfTexture = null;
913
1002
  model.VBOBuildTime = {};
@@ -922,7 +1011,7 @@ function extend(publicAPI, model) {
922
1011
  model.cutter = vtkCutter.newInstance();
923
1012
  model.lineToSurfaceFilter = vtkClosedPolyLineToSurfaceFilter.newInstance();
924
1013
  model.transform = vtkTransform.newInstance();
925
- get(publicAPI, model, ['openGLTexture']);
1014
+ get(publicAPI, model, ['scalarTextures']);
926
1015
 
927
1016
  // Object methods
928
1017
  vtkOpenGLImageResliceMapper(publicAPI, model);