@kitware/vtk.js 28.12.4 → 28.13.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.
@@ -29,7 +29,7 @@ function vtkImageReslice(publicAPI, model) {
29
29
  const superClass = {
30
30
  ...publicAPI
31
31
  };
32
- let indexMatrix = null;
32
+ const indexMatrix = mat4.identity(new Float64Array(16));
33
33
  let optimizedTransform = null;
34
34
  function getImageResliceSlabTrap(tmpPtr, inComponents, sampleCount, f) {
35
35
  const n = sampleCount - 1;
@@ -218,7 +218,7 @@ function vtkImageReslice(publicAPI, model) {
218
218
  let interpolationMode = model.interpolationMode;
219
219
  model.usePermuteExecute = false;
220
220
  if (model.optimization) {
221
- if (model.slabSliceSpacingFraction === 1.0 && model.interpolator.isSeparable() && publicAPI.isPermutationMatrix(indexMatrix)) {
221
+ if (optimizedTransform == null && model.slabSliceSpacingFraction === 1.0 && model.interpolator.isSeparable() && publicAPI.isPermutationMatrix(indexMatrix)) {
222
222
  model.usePermuteExecute = true;
223
223
  if (publicAPI.canUseNearestNeighbor(indexMatrix, outWholeExt)) {
224
224
  interpolationMode = InterpolationMode.NEAREST;
@@ -286,7 +286,7 @@ function vtkImageReslice(publicAPI, model) {
286
286
  const rescaleScalars = model.scalarShift !== 0.0 || model.scalarScale !== 1.0;
287
287
 
288
288
  // is nearest neighbor optimization possible?
289
- const optimizeNearest = interpolationMode === InterpolationMode.NEAREST && borderMode === ImageBorderMode.CLAMP && !(perspective || convertScalars != null || rescaleScalars) && inputScalarType === outScalars.getDataType() && fullSize === inScalars.getNumberOfTuples() && model.border === true && nsamples <= 1;
289
+ const optimizeNearest = interpolationMode === InterpolationMode.NEAREST && borderMode === ImageBorderMode.CLAMP && !(optimizedTransform != null || perspective || convertScalars != null || rescaleScalars) && inputScalarType === outScalars.getDataType() && fullSize === inScalars.getNumberOfTuples() && model.border === true && nsamples <= 1;
290
290
 
291
291
  // get pixel information
292
292
  const scalarType = outScalars.getDataType();
@@ -306,11 +306,6 @@ function vtkImageReslice(publicAPI, model) {
306
306
  origin[i] = newmat[4 * 3 + i];
307
307
  }
308
308
 
309
- // get the input origin and spacing for conversion purposes
310
- model.interpolator.getOrigin();
311
- const inSpacing = model.interpolator.getSpacing();
312
- [1.0 / inSpacing[0], 1.0 / inSpacing[1], 1.0 / inSpacing[2]];
313
-
314
309
  // allocate an output row of type double
315
310
  let floatPtr = null;
316
311
  if (!optimizeNearest) {
@@ -409,6 +404,16 @@ function vtkImageReslice(publicAPI, model) {
409
404
  inPoint[1] *= f;
410
405
  inPoint[2] *= f;
411
406
  }
407
+ if (optimizedTransform !== null) {
408
+ // get the input origin and spacing for conversion purposes
409
+ const inOrigin = model.interpolator.getOrigin();
410
+ const inSpacing = model.interpolator.getSpacing();
411
+ const inInvSpacing = [1.0 / inSpacing[0], 1.0 / inSpacing[1], 1.0 / inSpacing[2]];
412
+
413
+ // apply the AbstractTransform if there is one
414
+ // TBD: handle inDirection
415
+ publicAPI.applyTransform(optimizedTransform, inPoint, inOrigin, inInvSpacing);
416
+ }
412
417
  if (model.interpolator.checkBoundsIJK(inPoint)) {
413
418
  // do the interpolation
414
419
  isInBounds = 1;
@@ -541,63 +546,29 @@ function vtkImageReslice(publicAPI, model) {
541
546
  * @returns
542
547
  */
543
548
  publicAPI.getIndexMatrix = (input, output) => {
544
- // first verify that we have to update the matrix
545
- if (indexMatrix === null) {
546
- indexMatrix = mat4.identity(new Float64Array(16));
547
- }
548
- const inOrigin = input.getOrigin();
549
- const inSpacing = input.getSpacing();
550
- const inDirection = input.getDirection();
551
- const outOrigin = output.getOrigin();
552
- const outSpacing = output.getSpacing();
553
549
  const transform = mat4.identity(new Float64Array(16));
554
- const inMatrix = mat4.identity(new Float64Array(16));
555
- const outMatrix = mat4.identity(new Float64Array(16));
550
+ optimizedTransform = null;
556
551
  if (model.resliceAxes) {
557
552
  mat4.copy(transform, model.resliceAxes);
558
553
  }
559
554
  if (model.resliceTransform) {
560
555
  if (model.resliceTransform.isA('vtkHomogeneousTransform')) {
561
- // transform->PostMultiply();
562
- // transform->Concatenate(
563
- // mat4.multiply(transform, transform, model.resliceTransform.getMatrix());
564
556
  mat4.multiply(transform, model.resliceTransform.getMatrix(), transform);
565
557
  } else {
566
558
  // TODO
567
559
  vtkWarningMacro('Non homogeneous transform have not yet been ported');
568
560
  }
569
561
  }
570
- if (!vtkMath.isIdentity3x3(inDirection)) {
571
- const imageTransform = vtkMatrixBuilder.buildFromRadian().translate(inOrigin[0], inOrigin[1], inOrigin[2]).multiply3x3(inDirection).translate(-inOrigin[0], -inOrigin[1], -inOrigin[2]);
572
- mat4.multiply(transform, imageTransform.getMatrix(), transform);
573
- }
574
-
575
- // check to see if we have an identity matrix
576
- let isIdentity = vtkMath.isIdentity(transform);
577
562
 
578
563
  // the outMatrix takes OutputData indices to OutputData coordinates,
564
+ const outMatrix = output.getIndexToWorld();
565
+ mat4.multiply(transform, transform, outMatrix);
566
+
579
567
  // the inMatrix takes InputData coordinates to InputData indices
580
- for (let i = 0; i < 3; i++) {
581
- if ((inSpacing[i] !== outSpacing[i] || inOrigin[i] !== outOrigin[i]) || optimizedTransform != null ) {
582
- isIdentity = false;
583
- }
584
- inMatrix[4 * i + i] = 1.0 / inSpacing[i];
585
- inMatrix[4 * 3 + i] = -inOrigin[i] / inSpacing[i];
586
- outMatrix[4 * i + i] = outSpacing[i];
587
- outMatrix[4 * 3 + i] = outOrigin[i];
588
- }
589
- if (!isIdentity) {
590
- // transform.PreMultiply();
591
- // transform.Concatenate(outMatrix);
592
- mat4.multiply(transform, transform, outMatrix);
593
-
594
- // the optimizedTransform requires data coords, not
595
- // index coords, as its input
596
- {
597
- // transform->PostMultiply();
598
- // transform->Concatenate(inMatrix);
599
- mat4.multiply(transform, inMatrix, transform);
600
- }
568
+ // the optimizedTransform requires data coords, not index coords, as its input
569
+ if (optimizedTransform == null) {
570
+ const inMatrix = input.getWorldToIndex();
571
+ mat4.multiply(transform, inMatrix, transform);
601
572
  }
602
573
  mat4.copy(indexMatrix, transform);
603
574
  return indexMatrix;
@@ -123,6 +123,7 @@ function vtkFPSMonitor(publicAPI, model) {
123
123
  model.fpsSum -= model.buffer.shift();
124
124
  }
125
125
  renderTitle();
126
+ renderInfo();
126
127
  renderCanvas();
127
128
  }
128
129
 
@@ -257,6 +257,9 @@ function vtkView2DProxy(publicAPI, model) {
257
257
  }
258
258
  publicAPI.bindRepresentationToManipulator = representation => {
259
259
  let nbListeners = 0;
260
+ if (!representation.getProxyId) {
261
+ return nbListeners;
262
+ }
260
263
  model.rangeManipulator.removeAllListeners();
261
264
  model.sliceRepresentation = representation;
262
265
  while (model.sliceRepresentationSubscriptions.length) {
@@ -38,7 +38,9 @@ function vtkImageProperty(publicAPI, model) {
38
38
  };
39
39
 
40
40
  // Set the color of a volume to an RGB transfer function
41
- publicAPI.setRGBTransferFunction = (index, func) => {
41
+ publicAPI.setRGBTransferFunction = function () {
42
+ let index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
43
+ let func = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
42
44
  // backwards compatible call without the component index
43
45
  let idx = index;
44
46
  let transferFunc = func;
@@ -61,7 +63,9 @@ function vtkImageProperty(publicAPI, model) {
61
63
  };
62
64
 
63
65
  // Set the piecewise function
64
- publicAPI.setPiecewiseFunction = (index, func) => {
66
+ publicAPI.setPiecewiseFunction = function () {
67
+ let index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
68
+ let func = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
65
69
  let idx = index;
66
70
  let transferFunc = func;
67
71
  if (!Number.isInteger(index)) {
@@ -83,7 +87,9 @@ function vtkImageProperty(publicAPI, model) {
83
87
  };
84
88
 
85
89
  // Alias to set the piecewise function
86
- publicAPI.setScalarOpacity = (index, func) => {
90
+ publicAPI.setScalarOpacity = function () {
91
+ let index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
92
+ let func = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
87
93
  // backwards compatible call without the component index
88
94
  let idx = index;
89
95
  let transferFunc = func;
@@ -99,7 +105,9 @@ function vtkImageProperty(publicAPI, model) {
99
105
  let idx = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
100
106
  return publicAPI.getPiecewiseFunction(idx);
101
107
  };
102
- publicAPI.setComponentWeight = (index, value) => {
108
+ publicAPI.setComponentWeight = function () {
109
+ let index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
110
+ let value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
103
111
  if (index < 0 || index >= VTK_MAX_VRCOMP) {
104
112
  vtkErrorMacro('Invalid index');
105
113
  return false;
@@ -112,7 +120,8 @@ function vtkImageProperty(publicAPI, model) {
112
120
  }
113
121
  return false;
114
122
  };
115
- publicAPI.getComponentWeight = index => {
123
+ publicAPI.getComponentWeight = function () {
124
+ let index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
116
125
  if (index < 0 || index >= VTK_MAX_VRCOMP) {
117
126
  vtkErrorMacro('Invalid index');
118
127
  return 0.0;
@@ -116,6 +116,16 @@ function vtkMapper2D(publicAPI, model) {
116
116
  }
117
117
  model.colorBuildString = `${publicAPI.getMTime()}${scalars.getMTime()}${alpha}`;
118
118
  };
119
+ publicAPI.getPrimitiveCount = () => {
120
+ const input = publicAPI.getInputData();
121
+ const pcount = {
122
+ points: input.getPoints().getNumberOfValues() / 3,
123
+ verts: input.getVerts().getNumberOfValues() - input.getVerts().getNumberOfCells(),
124
+ lines: input.getLines().getNumberOfValues() - 2 * input.getLines().getNumberOfCells(),
125
+ triangles: input.getPolys().getNumberOfValues() - 3 * input.getPolys().getNumberOfCells()
126
+ };
127
+ return pcount;
128
+ };
119
129
  }
120
130
 
121
131
  // ----------------------------------------------------------------------------
@@ -94,22 +94,31 @@ function vtkRenderWindow(publicAPI, model) {
94
94
  publicAPI.getStatistics = () => {
95
95
  const results = {
96
96
  propCount: 0,
97
- invisiblePropCount: 0
97
+ invisiblePropCount: 0,
98
+ gpuMemoryMB: 0
98
99
  };
100
+ model._views.forEach(v => {
101
+ results.gpuMemoryMB += v.getGraphicsMemoryInfo() / 1e6;
102
+ });
99
103
  model.renderers.forEach(ren => {
100
104
  const props = ren.getViewProps();
105
+ const gren = model._views[0].getViewNodeFor(ren);
101
106
  props.forEach(prop => {
102
107
  if (prop.getVisibility()) {
103
108
  results.propCount += 1;
104
109
  const mpr = prop.getMapper && prop.getMapper();
105
110
  if (mpr && mpr.getPrimitiveCount) {
106
- const pcount = mpr.getPrimitiveCount();
107
- Object.keys(pcount).forEach(keyName => {
108
- if (!results[keyName]) {
109
- results[keyName] = 0;
110
- }
111
- results[keyName] += pcount[keyName];
112
- });
111
+ const gmpr = gren.getViewNodeFor(mpr);
112
+ if (gmpr) {
113
+ results.gpuMemoryMB += gmpr.getAllocatedGPUMemoryInBytes() / 1e6;
114
+ const pcount = mpr.getPrimitiveCount();
115
+ Object.keys(pcount).forEach(keyName => {
116
+ if (!results[keyName]) {
117
+ results[keyName] = 0;
118
+ }
119
+ results[keyName] += pcount[keyName];
120
+ });
121
+ }
113
122
  }
114
123
  } else {
115
124
  results.invisiblePropCount += 1;
@@ -63,7 +63,9 @@ function vtkVolumeProperty(publicAPI, model) {
63
63
  };
64
64
 
65
65
  // Set the color of a volume to a gray transfer function
66
- publicAPI.setGrayTransferFunction = (index, func) => {
66
+ publicAPI.setGrayTransferFunction = function () {
67
+ let index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
68
+ let func = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
67
69
  let modified = false;
68
70
  if (model.componentData[index].grayTransferFunction !== func) {
69
71
  model.componentData[index].grayTransferFunction = func;
@@ -80,7 +82,8 @@ function vtkVolumeProperty(publicAPI, model) {
80
82
  };
81
83
 
82
84
  // Get the currently set gray transfer function. Create one if none set.
83
- publicAPI.getGrayTransferFunction = index => {
85
+ publicAPI.getGrayTransferFunction = function () {
86
+ let index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
84
87
  if (model.componentData[index].grayTransferFunction === null) {
85
88
  model.componentData[index].grayTransferFunction = vtkPiecewiseFunction.newInstance();
86
89
  model.componentData[index].grayTransferFunction.addPoint(0, 0.0);
@@ -94,7 +97,9 @@ function vtkVolumeProperty(publicAPI, model) {
94
97
  };
95
98
 
96
99
  // Set the color of a volume to an RGB transfer function
97
- publicAPI.setRGBTransferFunction = (index, func) => {
100
+ publicAPI.setRGBTransferFunction = function () {
101
+ let index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
102
+ let func = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
98
103
  let modified = false;
99
104
  if (model.componentData[index].rGBTransferFunction !== func) {
100
105
  model.componentData[index].rGBTransferFunction = func;
@@ -111,7 +116,8 @@ function vtkVolumeProperty(publicAPI, model) {
111
116
  };
112
117
 
113
118
  // Get the currently set RGB transfer function. Create one if none set.
114
- publicAPI.getRGBTransferFunction = index => {
119
+ publicAPI.getRGBTransferFunction = function () {
120
+ let index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
115
121
  if (model.componentData[index].rGBTransferFunction === null) {
116
122
  model.componentData[index].rGBTransferFunction = vtkColorTransferFunction.newInstance();
117
123
  model.componentData[index].rGBTransferFunction.addRGBPoint(0, 0.0, 0.0, 0.0);
@@ -125,7 +131,9 @@ function vtkVolumeProperty(publicAPI, model) {
125
131
  };
126
132
 
127
133
  // Set the scalar opacity of a volume to a transfer function
128
- publicAPI.setScalarOpacity = (index, func) => {
134
+ publicAPI.setScalarOpacity = function () {
135
+ let index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
136
+ let func = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
129
137
  if (model.componentData[index].scalarOpacity !== func) {
130
138
  model.componentData[index].scalarOpacity = func;
131
139
  publicAPI.modified();
@@ -135,7 +143,8 @@ function vtkVolumeProperty(publicAPI, model) {
135
143
  };
136
144
 
137
145
  // Get the scalar opacity transfer function. Create one if none set.
138
- publicAPI.getScalarOpacity = index => {
146
+ publicAPI.getScalarOpacity = function () {
147
+ let index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
139
148
  if (model.componentData[index].scalarOpacity === null) {
140
149
  model.componentData[index].scalarOpacity = vtkPiecewiseFunction.newInstance();
141
150
  model.componentData[index].scalarOpacity.addPoint(0, 1.0);
@@ -144,7 +153,9 @@ function vtkVolumeProperty(publicAPI, model) {
144
153
  }
145
154
  return model.componentData[index].scalarOpacity;
146
155
  };
147
- publicAPI.setComponentWeight = (index, value) => {
156
+ publicAPI.setComponentWeight = function () {
157
+ let index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
158
+ let value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
148
159
  if (index < 0 || index >= VTK_MAX_VRCOMP) {
149
160
  vtkErrorMacro('Invalid index');
150
161
  return false;
@@ -157,7 +168,8 @@ function vtkVolumeProperty(publicAPI, model) {
157
168
  }
158
169
  return false;
159
170
  };
160
- publicAPI.getComponentWeight = index => {
171
+ publicAPI.getComponentWeight = function () {
172
+ let index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
161
173
  if (index < 0 || index >= VTK_MAX_VRCOMP) {
162
174
  vtkErrorMacro('Invalid index');
163
175
  return 0.0;
@@ -70,6 +70,7 @@ function vtkOpenGLBufferObject(publicAPI, model) {
70
70
  }
71
71
  model.context.bindBuffer(convertType(internalType), internalHandle);
72
72
  model.context.bufferData(convertType(internalType), data, model.context.STATIC_DRAW);
73
+ model.allocatedGPUMemoryInBytes = data.length * data.BYTES_PER_ELEMENT;
73
74
  dirty = false;
74
75
  return true;
75
76
  };
@@ -92,6 +93,7 @@ function vtkOpenGLBufferObject(publicAPI, model) {
92
93
  model.context.bindBuffer(convertType(internalType), null);
93
94
  model.context.deleteBuffer(internalHandle);
94
95
  internalHandle = null;
96
+ model.allocatedGPUMemoryInBytes = 0;
95
97
  }
96
98
  };
97
99
  publicAPI.setOpenGLRenderWindow = rw => {
@@ -115,7 +117,8 @@ function vtkOpenGLBufferObject(publicAPI, model) {
115
117
  const DEFAULT_VALUES = {
116
118
  objectType: ObjectType.ARRAY_BUFFER,
117
119
  // _openGLRenderWindow: null,
118
- context: null
120
+ context: null,
121
+ allocatedGPUMemoryInBytes: 0
119
122
  };
120
123
 
121
124
  // ----------------------------------------------------------------------------
@@ -126,7 +129,7 @@ function extend(publicAPI, model) {
126
129
 
127
130
  // Object methods
128
131
  macro.obj(publicAPI, model);
129
- macro.get(publicAPI, model, ['_openGLRenderWindow']);
132
+ macro.get(publicAPI, model, ['_openGLRenderWindow', 'allocatedGPUMemoryInBytes']);
130
133
  macro.moveToProtected(publicAPI, model, ['openGLRenderWindow']);
131
134
  vtkOpenGLBufferObject(publicAPI, model);
132
135
  }
@@ -168,6 +168,7 @@ function vtkOpenGLHelper(publicAPI, model) {
168
168
  }
169
169
  return 6;
170
170
  };
171
+ publicAPI.getAllocatedGPUMemoryInBytes = () => publicAPI.getCABO().getAllocatedGPUMemoryInBytes();
171
172
  }
172
173
 
173
174
  // ----------------------------------------------------------------------------
@@ -27,11 +27,10 @@ const {
27
27
  // helper methods
28
28
  // ----------------------------------------------------------------------------
29
29
 
30
- function computeFnToString(property, fn, numberOfComponents) {
31
- const pwfun = fn.apply(property);
30
+ function computeFnToString(property, pwfun, numberOfComponents) {
32
31
  if (pwfun) {
33
32
  const iComps = property.getIndependentComponents();
34
- return `${property.getMTime()}-${iComps}-${numberOfComponents}`;
33
+ return `${pwfun.getMTime()}-${iComps}-${numberOfComponents}`;
35
34
  }
36
35
  return '0';
37
36
  }
@@ -51,9 +50,6 @@ function vtkOpenGLImageMapper(publicAPI, model) {
51
50
  model._openGLRenderWindow = model._openGLRenderer.getParent();
52
51
  model.context = model._openGLRenderWindow.getContext();
53
52
  model.tris.setOpenGLRenderWindow(model._openGLRenderWindow);
54
- model.openGLTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
55
- model.colorTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
56
- model.pwfTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
57
53
  const ren = model._openGLRenderer.getRenderable();
58
54
  model.openGLCamera = model._openGLRenderer.getViewNodeFor(ren.getActiveCamera());
59
55
  // is slice set by the camera
@@ -226,7 +222,7 @@ function vtkOpenGLImageMapper(publicAPI, model) {
226
222
  if (!model.currentRenderPass && model.lastRenderPassShaderReplacement || model.currentRenderPass && model.currentRenderPass.getShaderReplacement() !== model.lastRenderPassShaderReplacement) {
227
223
  needRebuild = true;
228
224
  }
229
- if (needRebuild || model.lastHaveSeenDepthRequest !== model.haveSeenDepthRequest || cellBO.getProgram() === 0 || model.lastTextureComponents !== tNumComp || model.lastIndependentComponents !== iComp) {
225
+ if (needRebuild || model.lastHaveSeenDepthRequest !== model.haveSeenDepthRequest || cellBO.getProgram()?.getHandle() === 0 || model.lastTextureComponents !== tNumComp || model.lastIndependentComponents !== iComp) {
230
226
  model.lastHaveSeenDepthRequest = model.haveSeenDepthRequest;
231
227
  model.lastTextureComponents = tNumComp;
232
228
  model.lastIndependentComponents = iComp;
@@ -474,33 +470,34 @@ function vtkOpenGLImageMapper(publicAPI, model) {
474
470
  const dataType = imgScalars.getDataType();
475
471
  const numComp = imgScalars.getNumberOfComponents();
476
472
  const actorProperty = actor.getProperty();
477
-
478
- // set interpolation on the texture based on property setting
479
473
  const iType = actorProperty.getInterpolationType();
480
- if (iType === InterpolationType.NEAREST) {
481
- model.colorTexture.setMinificationFilter(Filter.NEAREST);
482
- model.colorTexture.setMagnificationFilter(Filter.NEAREST);
483
- model.pwfTexture.setMinificationFilter(Filter.NEAREST);
484
- model.pwfTexture.setMagnificationFilter(Filter.NEAREST);
485
- } else {
486
- model.colorTexture.setMinificationFilter(Filter.LINEAR);
487
- model.colorTexture.setMagnificationFilter(Filter.LINEAR);
488
- model.pwfTexture.setMinificationFilter(Filter.LINEAR);
489
- model.pwfTexture.setMagnificationFilter(Filter.LINEAR);
490
- }
491
474
  const iComps = actorProperty.getIndependentComponents();
492
475
  const numIComps = iComps ? numComp : 1;
493
476
  const textureHeight = iComps ? 2 * numIComps : 1;
494
- const cfunToString = computeFnToString(actorProperty, actorProperty.getRGBTransferFunction, numIComps);
495
- if (model.colorTextureString !== cfunToString) {
477
+ const colorTransferFunc = actorProperty.getRGBTransferFunction();
478
+ const cfunToString = computeFnToString(actorProperty, colorTransferFunc, numIComps);
479
+ const cTex = model._openGLRenderWindow.getGraphicsResourceForObject(colorTransferFunc);
480
+ const reBuildC = !cTex?.vtkObj || cTex?.hash !== cfunToString || model.colorTextureString !== cfunToString;
481
+ if (reBuildC) {
496
482
  const cWidth = 1024;
497
483
  const cSize = cWidth * textureHeight * 3;
498
484
  const cTable = new Uint8Array(cSize);
499
- let cfun = actorProperty.getRGBTransferFunction();
500
- if (cfun) {
485
+ if (!model.colorTexture) {
486
+ model.colorTexture = vtkOpenGLTexture.newInstance();
487
+ model.colorTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
488
+ }
489
+ // set interpolation on the texture based on property setting
490
+ if (iType === InterpolationType.NEAREST) {
491
+ model.colorTexture.setMinificationFilter(Filter.NEAREST);
492
+ model.colorTexture.setMagnificationFilter(Filter.NEAREST);
493
+ } else {
494
+ model.colorTexture.setMinificationFilter(Filter.LINEAR);
495
+ model.colorTexture.setMagnificationFilter(Filter.LINEAR);
496
+ }
497
+ if (colorTransferFunc) {
501
498
  const tmpTable = new Float32Array(cWidth * 3);
502
499
  for (let c = 0; c < numIComps; c++) {
503
- cfun = actorProperty.getRGBTransferFunction(c);
500
+ const cfun = actorProperty.getRGBTransferFunction(c);
504
501
  const cRange = cfun.getRange();
505
502
  cfun.getTable(cRange[0], cRange[1], cWidth, tmpTable, 1);
506
503
  if (iComps) {
@@ -514,6 +511,8 @@ function vtkOpenGLImageMapper(publicAPI, model) {
514
511
  }
515
512
  }
516
513
  }
514
+ model.colorTexture.releaseGraphicsResources(model._openGLRenderWindow);
515
+ model.colorTexture.resetFormatAndType();
517
516
  model.colorTexture.create2DFromRaw(cWidth, textureHeight, 3, VtkDataTypes.UNSIGNED_CHAR, cTable);
518
517
  } else {
519
518
  for (let i = 0; i < cWidth * 3; ++i) {
@@ -524,24 +523,43 @@ function vtkOpenGLImageMapper(publicAPI, model) {
524
523
  model.colorTexture.create2DFromRaw(cWidth, 1, 3, VtkDataTypes.UNSIGNED_CHAR, cTable);
525
524
  }
526
525
  model.colorTextureString = cfunToString;
526
+ if (colorTransferFunc) {
527
+ model._openGLRenderWindow.setGraphicsResourceForObject(colorTransferFunc, model.colorTexture, model.colorTextureString);
528
+ }
529
+ } else {
530
+ model.colorTexture = cTex.vtkObj;
531
+ model.colorTextureString = cTex.hash;
527
532
  }
528
533
 
529
534
  // Build piecewise function buffer. This buffer is used either
530
535
  // for component weighting or opacity, depending on whether we're
531
536
  // rendering components independently or not.
532
- const pwfunToString = computeFnToString(actorProperty, actorProperty.getPiecewiseFunction, numIComps);
533
- if (model.pwfTextureString !== pwfunToString) {
537
+ const pwFunc = actorProperty.getPiecewiseFunction();
538
+ const pwfunToString = computeFnToString(actorProperty, pwFunc, numIComps);
539
+ const pwfTex = model._openGLRenderWindow.getGraphicsResourceForObject(pwFunc);
540
+ // rebuild opacity tfun?
541
+ const reBuildPwf = !pwfTex?.vtkObj || pwfTex?.hash !== pwfunToString || model.pwfTextureString !== pwfunToString;
542
+ if (reBuildPwf) {
534
543
  const pwfWidth = 1024;
535
544
  const pwfSize = pwfWidth * textureHeight;
536
545
  const pwfTable = new Uint8Array(pwfSize);
537
- let pwfun = actorProperty.getPiecewiseFunction();
538
- // support case where pwfun is added/removed
539
- model.pwfTexture.resetFormatAndType();
540
- if (pwfun) {
546
+ if (!model.pwfTexture) {
547
+ model.pwfTexture = vtkOpenGLTexture.newInstance();
548
+ model.pwfTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
549
+ }
550
+ // set interpolation on the texture based on property setting
551
+ if (iType === InterpolationType.NEAREST) {
552
+ model.pwfTexture.setMinificationFilter(Filter.NEAREST);
553
+ model.pwfTexture.setMagnificationFilter(Filter.NEAREST);
554
+ } else {
555
+ model.pwfTexture.setMinificationFilter(Filter.LINEAR);
556
+ model.pwfTexture.setMagnificationFilter(Filter.LINEAR);
557
+ }
558
+ if (pwFunc) {
541
559
  const pwfFloatTable = new Float32Array(pwfSize);
542
560
  const tmpTable = new Float32Array(pwfWidth);
543
561
  for (let c = 0; c < numIComps; ++c) {
544
- pwfun = actorProperty.getPiecewiseFunction(c);
562
+ const pwfun = actorProperty.getPiecewiseFunction(c);
545
563
  if (pwfun === null) {
546
564
  // Piecewise constant max if no function supplied for this component
547
565
  pwfFloatTable.fill(1.0);
@@ -561,6 +579,8 @@ function vtkOpenGLImageMapper(publicAPI, model) {
561
579
  }
562
580
  }
563
581
  }
582
+ model.pwfTexture.releaseGraphicsResources(model._openGLRenderWindow);
583
+ model.pwfTexture.resetFormatAndType();
564
584
  model.pwfTexture.create2DFromRaw(pwfWidth, textureHeight, 1, VtkDataTypes.FLOAT, pwfFloatTable);
565
585
  } else {
566
586
  // default is opaque
@@ -568,6 +588,12 @@ function vtkOpenGLImageMapper(publicAPI, model) {
568
588
  model.pwfTexture.create2DFromRaw(pwfWidth, 1, 1, VtkDataTypes.UNSIGNED_CHAR, pwfTable);
569
589
  }
570
590
  model.pwfTextureString = pwfunToString;
591
+ if (pwFunc) {
592
+ model._openGLRenderWindow.setGraphicsResourceForObject(pwFunc, model.pwfTexture, model.pwfTextureString);
593
+ }
594
+ } else {
595
+ model.pwfTexture = pwfTex.vtkObj;
596
+ model.pwfTextureString = pwfTex.hash;
571
597
  }
572
598
 
573
599
  // Find what IJK axis and what direction to slice along
@@ -605,6 +631,10 @@ function vtkOpenGLImageMapper(publicAPI, model) {
605
631
  if (model.VBOBuildString !== toString) {
606
632
  // Build the VBOs
607
633
  const dims = image.getDimensions();
634
+ if (!model.openGLTexture) {
635
+ model.openGLTexture = vtkOpenGLTexture.newInstance();
636
+ model.openGLTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
637
+ }
608
638
  if (iType === InterpolationType.NEAREST) {
609
639
  if (new Set([1, 3, 4]).has(numComp) && dataType === VtkDataTypes.UNSIGNED_CHAR && !iComps) {
610
640
  model.openGLTexture.setGenerateMipmap(true);
@@ -710,7 +740,19 @@ function vtkOpenGLImageMapper(publicAPI, model) {
710
740
  } else {
711
741
  vtkErrorMacro('Reformat slicing not yet supported.');
712
742
  }
713
- model.openGLTexture.create2DFilterableFromRaw(dims[0], dims[1], numComp, imgScalars.getDataType(), scalars, model.renderable.getPreferSizeOverAccuracy?.());
743
+ const tex = model._openGLRenderWindow.getGraphicsResourceForObject(scalars);
744
+ if (!tex?.vtkObj) {
745
+ if (model._scalars !== scalars) {
746
+ model._openGLRenderWindow.releaseGraphicsResourcesForObject(model._scalars);
747
+ model._scalars = scalars;
748
+ }
749
+ model.openGLTexture.resetFormatAndType();
750
+ model.openGLTexture.create2DFilterableFromRaw(dims[0], dims[1], numComp, imgScalars.getDataType(), scalars, model.renderable.getPreferSizeOverAccuracy?.());
751
+ model._openGLRenderWindow.setGraphicsResourceForObject(scalars, model.openGLTexture, model.VBOBuildString);
752
+ } else {
753
+ model.openGLTexture = tex.vtkObj;
754
+ model.VBOBuildString = tex.hash;
755
+ }
714
756
  model.openGLTexture.activate();
715
757
  model.openGLTexture.sendParameters();
716
758
  model.openGLTexture.deactivate();
@@ -763,7 +805,8 @@ const DEFAULT_VALUES = {
763
805
  pwfTexture: null,
764
806
  lastHaveSeenDepthRequest: false,
765
807
  haveSeenDepthRequest: false,
766
- lastTextureComponents: 0
808
+ lastTextureComponents: 0,
809
+ _scalars: null
767
810
  };
768
811
 
769
812
  // ----------------------------------------------------------------------------
@@ -777,15 +820,6 @@ function extend(publicAPI, model) {
777
820
  vtkReplacementShaderMapper.implementReplaceShaderCoincidentOffset(publicAPI, model, initialValues);
778
821
  vtkReplacementShaderMapper.implementBuildShadersWithReplacements(publicAPI, model, initialValues);
779
822
  model.tris = vtkHelper.newInstance();
780
- model.openGLTexture = vtkOpenGLTexture.newInstance({
781
- resizable: true
782
- });
783
- model.colorTexture = vtkOpenGLTexture.newInstance({
784
- resizable: true
785
- });
786
- model.pwfTexture = vtkOpenGLTexture.newInstance({
787
- resizable: true
788
- });
789
823
  model.imagemat = mat4.identity(new Float64Array(16));
790
824
  model.imagematinv = mat4.identity(new Float64Array(16));
791
825