@kitware/vtk.js 32.0.1 → 32.1.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.
@@ -285,7 +285,7 @@ function vtkOpenGLTexture(publicAPI, model) {
285
285
  publicAPI.getDefaultInternalFormat = (vtktype, numComps) => {
286
286
  let result = 0;
287
287
  // try default next
288
- result = model._openGLRenderWindow.getDefaultTextureInternalFormat(vtktype, numComps, model.oglNorm16Ext, model.useHalfFloat);
288
+ result = model._openGLRenderWindow.getDefaultTextureInternalFormat(vtktype, numComps, model.oglNorm16Ext, publicAPI.useHalfFloat());
289
289
  if (result) {
290
290
  return result;
291
291
  }
@@ -295,6 +295,7 @@ function vtkOpenGLTexture(publicAPI, model) {
295
295
  }
296
296
  return result;
297
297
  };
298
+ publicAPI.useHalfFloat = () => model.enableUseHalfFloat && model.canUseHalfFloat;
298
299
 
299
300
  //----------------------------------------------------------------------------
300
301
  publicAPI.setInternalFormat = iFormat => {
@@ -353,6 +354,7 @@ function vtkOpenGLTexture(publicAPI, model) {
353
354
 
354
355
  //----------------------------------------------------------------------------
355
356
  publicAPI.getDefaultDataType = vtkScalarType => {
357
+ const useHalfFloat = publicAPI.useHalfFloat();
356
358
  // DON'T DEAL with VTK_CHAR as this is platform dependent.
357
359
  if (model._openGLRenderWindow.getWebgl2()) {
358
360
  switch (vtkScalarType) {
@@ -362,14 +364,14 @@ function vtkOpenGLTexture(publicAPI, model) {
362
364
  return model.context.UNSIGNED_BYTE;
363
365
  // prefer norm16 since that is accurate compared to
364
366
  // half float which is not
365
- case model.oglNorm16Ext && !model.useHalfFloat && VtkDataTypes.SHORT:
367
+ case model.oglNorm16Ext && !useHalfFloat && VtkDataTypes.SHORT:
366
368
  return model.context.SHORT;
367
- case model.oglNorm16Ext && !model.useHalfFloat && VtkDataTypes.UNSIGNED_SHORT:
369
+ case model.oglNorm16Ext && !useHalfFloat && VtkDataTypes.UNSIGNED_SHORT:
368
370
  return model.context.UNSIGNED_SHORT;
369
371
  // use half float type
370
- case model.useHalfFloat && VtkDataTypes.SHORT:
372
+ case useHalfFloat && VtkDataTypes.SHORT:
371
373
  return model.context.HALF_FLOAT;
372
- case model.useHalfFloat && VtkDataTypes.UNSIGNED_SHORT:
374
+ case useHalfFloat && VtkDataTypes.UNSIGNED_SHORT:
373
375
  return model.context.HALF_FLOAT;
374
376
  // case VtkDataTypes.INT:
375
377
  // return model.context.INT;
@@ -490,8 +492,18 @@ function vtkOpenGLTexture(publicAPI, model) {
490
492
  }
491
493
  };
492
494
 
493
- //----------------------------------------------------------------------------
494
- function updateArrayDataType(dataType, data) {
495
+ /**
496
+ * Updates the data array to match the required data type for OpenGL.
497
+ *
498
+ * This function takes the input data and converts it to the appropriate
499
+ * format required by the OpenGL texture, based on the specified data type.
500
+ *
501
+ * @param {string} dataType - The original data type of the input data.
502
+ * @param {Array} data - The input data array that needs to be updated.
503
+ * @param {boolean} [depth=false] - Indicates whether the data is a 3D array.
504
+ * @returns {Array} The updated data array that matches the OpenGL data type.
505
+ */
506
+ publicAPI.updateArrayDataTypeForGL = function (dataType, data) {
495
507
  let depth = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
496
508
  const pixData = [];
497
509
  let pixCount = model.width * model.height * model.components;
@@ -556,7 +568,7 @@ function vtkOpenGLTexture(publicAPI, model) {
556
568
  }
557
569
  }
558
570
  return pixData;
559
- }
571
+ };
560
572
 
561
573
  //----------------------------------------------------------------------------
562
574
  function scaleTextureToHighestPowerOfTwo(data) {
@@ -683,7 +695,7 @@ function vtkOpenGLTexture(publicAPI, model) {
683
695
 
684
696
  // Create an array of texture with one texture
685
697
  const dataArray = [data];
686
- const pixData = updateArrayDataType(dataType, dataArray);
698
+ const pixData = publicAPI.updateArrayDataTypeForGL(dataType, dataArray);
687
699
  const scaledData = scaleTextureToHighestPowerOfTwo(pixData);
688
700
 
689
701
  // Source texture data from the PBO.
@@ -705,7 +717,7 @@ function vtkOpenGLTexture(publicAPI, model) {
705
717
  if (flip) {
706
718
  model.context.pixelStorei(model.context.UNPACK_FLIP_Y_WEBGL, false);
707
719
  }
708
- model.allocatedGPUMemoryInBytes = model.width * model.height * model.depth * numComps * model._openGLRenderWindow.getDefaultTextureByteSize(dataType, model.oglNorm16Ext, model.useHalfFloat);
720
+ model.allocatedGPUMemoryInBytes = model.width * model.height * model.depth * numComps * model._openGLRenderWindow.getDefaultTextureByteSize(dataType, model.oglNorm16Ext, publicAPI.useHalfFloat());
709
721
  publicAPI.deactivate();
710
722
  return true;
711
723
  };
@@ -730,7 +742,7 @@ function vtkOpenGLTexture(publicAPI, model) {
730
742
  model.maxLevel = data.length / 6 - 1;
731
743
  publicAPI.createTexture();
732
744
  publicAPI.bind();
733
- const pixData = updateArrayDataType(dataType, data);
745
+ const pixData = publicAPI.updateArrayDataTypeForGL(dataType, data);
734
746
  const scaledData = scaleTextureToHighestPowerOfTwo(pixData);
735
747
 
736
748
  // invert the data because opengl is messed up with cube maps
@@ -783,7 +795,7 @@ function vtkOpenGLTexture(publicAPI, model) {
783
795
  h /= 2;
784
796
  }
785
797
  }
786
- model.allocatedGPUMemoryInBytes = model.width * model.height * model.depth * numComps * model._openGLRenderWindow.getDefaultTextureByteSize(dataType, model.oglNorm16Ext, model.useHalfFloat);
798
+ model.allocatedGPUMemoryInBytes = model.width * model.height * model.depth * numComps * model._openGLRenderWindow.getDefaultTextureByteSize(dataType, model.oglNorm16Ext, publicAPI.useHalfFloat());
787
799
  // generateMipmap must not be called here because we manually upload all levels
788
800
  // if it is called, all levels will be overwritten
789
801
 
@@ -833,7 +845,7 @@ function vtkOpenGLTexture(publicAPI, model) {
833
845
  if (model.generateMipmap) {
834
846
  model.context.generateMipmap(model.target);
835
847
  }
836
- model.allocatedGPUMemoryInBytes = model.width * model.height * model.depth * model.components * model._openGLRenderWindow.getDefaultTextureByteSize(dataType, model.oglNorm16Ext, model.useHalfFloat);
848
+ model.allocatedGPUMemoryInBytes = model.width * model.height * model.depth * model.components * model._openGLRenderWindow.getDefaultTextureByteSize(dataType, model.oglNorm16Ext, publicAPI.useHalfFloat());
837
849
  publicAPI.deactivate();
838
850
  return true;
839
851
  };
@@ -883,7 +895,7 @@ function vtkOpenGLTexture(publicAPI, model) {
883
895
  if (model.generateMipmap) {
884
896
  model.context.generateMipmap(model.target);
885
897
  }
886
- model.allocatedGPUMemoryInBytes = model.width * model.height * model.depth * model.components * model._openGLRenderWindow.getDefaultTextureByteSize(VtkDataTypes.UNSIGNED_CHAR, model.oglNorm16Ext, model.useHalfFloat);
898
+ model.allocatedGPUMemoryInBytes = model.width * model.height * model.depth * model.components * model._openGLRenderWindow.getDefaultTextureByteSize(VtkDataTypes.UNSIGNED_CHAR, model.oglNorm16Ext, publicAPI.useHalfFloat());
887
899
  publicAPI.deactivate();
888
900
  return true;
889
901
  };
@@ -915,20 +927,23 @@ function vtkOpenGLTexture(publicAPI, model) {
915
927
  }
916
928
  return true;
917
929
  }
918
- function setUseHalfFloat(dataType, offset, scale, preferSizeOverAccuracy) {
930
+ function setCanUseHalfFloat(dataType, offset, scale, preferSizeOverAccuracy) {
919
931
  publicAPI.getOpenGLDataType(dataType);
932
+
933
+ // Don't consider halfFloat and convert back to Float when the range of data does not generate an accurate halfFloat
934
+ // AND it is not preferable to have a smaller texture than an exact texture.
935
+ const isExactHalfFloat = hasExactHalfFloat(offset, scale) || preferSizeOverAccuracy;
920
936
  let useHalfFloat = false;
921
937
  if (model._openGLRenderWindow.getWebgl2()) {
922
- useHalfFloat = model.openGLDataType === model.context.HALF_FLOAT;
938
+ // If OES_texture_float_linear is not available, and using a half float would still be exact, force half floats
939
+ // This is because half floats are always texture filterable in webgl2, while full *32F floats are not (unless the extension is present)
940
+ const forceHalfFloat = model.openGLDataType === model.context.FLOAT && model.context.getExtension('OES_texture_float_linear') === null && isExactHalfFloat;
941
+ useHalfFloat = forceHalfFloat || model.openGLDataType === model.context.HALF_FLOAT;
923
942
  } else {
924
943
  const halfFloatExt = model.context.getExtension('OES_texture_half_float');
925
944
  useHalfFloat = halfFloatExt && model.openGLDataType === halfFloatExt.HALF_FLOAT_OES;
926
945
  }
927
-
928
- // Don't consider halfFloat and convert back to Float when the range of data does not generate an accurate halfFloat
929
- // AND it is not preferable to have a smaller texture than an exact texture.
930
- const isHalfFloat = useHalfFloat && (hasExactHalfFloat(offset, scale) || preferSizeOverAccuracy);
931
- model.useHalfFloat = isHalfFloat;
946
+ model.canUseHalfFloat = useHalfFloat && isExactHalfFloat;
932
947
  }
933
948
  function processDataArray(dataArray, preferSizeOverAccuracy) {
934
949
  const numComps = dataArray.getNumberOfComponents();
@@ -948,11 +963,11 @@ function vtkOpenGLTexture(publicAPI, model) {
948
963
 
949
964
  // preferSizeOverAccuracy will override norm16 due to bug with norm16 implementation
950
965
  // https://bugs.chromium.org/p/chromium/issues/detail?id=1408247
951
- setUseHalfFloat(dataType, scaleOffsets.offset, scaleOffsets.scale, preferSizeOverAccuracy);
966
+ setCanUseHalfFloat(dataType, scaleOffsets.offset, scaleOffsets.scale, preferSizeOverAccuracy);
952
967
 
953
968
  // since our default is to use half float, in case that we can't use it
954
969
  // we need to use another type
955
- if (!model.useHalfFloat) {
970
+ if (!publicAPI.useHalfFloat()) {
956
971
  publicAPI.getOpenGLDataType(dataType, true);
957
972
  }
958
973
  return {
@@ -979,14 +994,88 @@ function vtkOpenGLTexture(publicAPI, model) {
979
994
  } = processDataArray(dataArray, preferSizeOverAccuracy);
980
995
  publicAPI.create2DFromRaw(width, height, numComps, dataType, data);
981
996
  };
997
+ publicAPI.updateVolumeInfoForGL = (dataType, numComps) => {
998
+ let isScalingApplied = false;
999
+ const useHalfFloat = publicAPI.useHalfFloat();
1000
+
1001
+ // Initialize volume info if it doesn't exist
1002
+ if (!model.volumeInfo?.scale || !model.volumeInfo?.offset) {
1003
+ model.volumeInfo = {
1004
+ scale: new Array(numComps),
1005
+ offset: new Array(numComps)
1006
+ };
1007
+ }
1008
+
1009
+ // Default scaling and offset
1010
+ for (let c = 0; c < numComps; ++c) {
1011
+ model.volumeInfo.scale[c] = 1.0;
1012
+ model.volumeInfo.offset[c] = 0.0;
1013
+ }
1014
+
1015
+ // Handle SHORT data type with EXT_texture_norm16 extension
1016
+ if (model.oglNorm16Ext && !useHalfFloat && dataType === VtkDataTypes.SHORT) {
1017
+ for (let c = 0; c < numComps; ++c) {
1018
+ model.volumeInfo.scale[c] = 32767.0; // Scale to [-1, 1] range
1019
+ }
1020
+
1021
+ isScalingApplied = true;
1022
+ }
1023
+
1024
+ // Handle UNSIGNED_SHORT data type with EXT_texture_norm16 extension
1025
+ if (model.oglNorm16Ext && !useHalfFloat && dataType === VtkDataTypes.UNSIGNED_SHORT) {
1026
+ for (let c = 0; c < numComps; ++c) {
1027
+ model.volumeInfo.scale[c] = 65535.0; // Scale to [0, 1] range
1028
+ }
1029
+
1030
+ isScalingApplied = true;
1031
+ }
1032
+
1033
+ // Handle UNSIGNED_CHAR data type
1034
+ if (dataType === VtkDataTypes.UNSIGNED_CHAR) {
1035
+ for (let c = 0; c < numComps; ++c) {
1036
+ model.volumeInfo.scale[c] = 255.0; // Scale to [0, 1] range
1037
+ }
1038
+
1039
+ isScalingApplied = true;
1040
+ }
1041
+
1042
+ // No scaling needed for FLOAT or HalfFloat (SHORT/UNSIGNED_SHORT)
1043
+ if (dataType === VtkDataTypes.FLOAT || useHalfFloat && (dataType === VtkDataTypes.SHORT || dataType === VtkDataTypes.UNSIGNED_SHORT)) {
1044
+ isScalingApplied = true;
1045
+ }
1046
+ return isScalingApplied;
1047
+ };
1048
+
982
1049
  //----------------------------------------------------------------------------
983
1050
  publicAPI.create3DFromRaw = (width, height, depth, numComps, dataType, data) => {
1051
+ let dataTypeToUse = dataType;
1052
+ let dataToUse = data;
1053
+ if (!publicAPI.updateVolumeInfoForGL(dataTypeToUse, numComps) && dataToUse) {
1054
+ const numPixelsIn = width * height * depth;
1055
+ const scaleOffsetsCopy = structuredClone(model.volumeInfo);
1056
+ // otherwise convert to float
1057
+ const newArray = new Float32Array(numPixelsIn * numComps);
1058
+ // use computed scale and offset
1059
+ model.volumeInfo.offset = scaleOffsetsCopy.offset;
1060
+ model.volumeInfo.scale = scaleOffsetsCopy.scale;
1061
+ let count = 0;
1062
+ const scaleInverse = scaleOffsetsCopy.scale.map(s => 1 / s);
1063
+ for (let i = 0; i < numPixelsIn; i++) {
1064
+ for (let nc = 0; nc < numComps; nc++) {
1065
+ newArray[count] = (dataToUse[count] - scaleOffsetsCopy.offset[nc]) * scaleInverse[nc];
1066
+ count++;
1067
+ }
1068
+ }
1069
+ dataTypeToUse = VtkDataTypes.FLOAT;
1070
+ dataToUse = newArray;
1071
+ }
1072
+
984
1073
  // Permit OpenGLDataType to be half float, if applicable, for 3D
985
- publicAPI.getOpenGLDataType(dataType);
1074
+ publicAPI.getOpenGLDataType(dataTypeToUse);
986
1075
 
987
1076
  // Now determine the texture parameters using the arguments.
988
- publicAPI.getInternalFormat(dataType, numComps);
989
- publicAPI.getFormat(dataType, numComps);
1077
+ publicAPI.getInternalFormat(dataTypeToUse, numComps);
1078
+ publicAPI.getFormat(dataTypeToUse, numComps);
990
1079
  if (!model.internalFormat || !model.format || !model.openGLDataType) {
991
1080
  vtkErrorMacro('Failed to determine texture parameters.');
992
1081
  return false;
@@ -1001,9 +1090,9 @@ function vtkOpenGLTexture(publicAPI, model) {
1001
1090
  publicAPI.createTexture();
1002
1091
  publicAPI.bind();
1003
1092
  // Create an array of texture with one texture
1004
- const dataArray = [data];
1093
+ const dataArray = [dataToUse];
1005
1094
  const is3DArray = true;
1006
- const pixData = updateArrayDataType(dataType, dataArray, is3DArray);
1095
+ const pixData = publicAPI.updateArrayDataTypeForGL(dataTypeToUse, dataArray, is3DArray);
1007
1096
  const scaledData = scaleTextureToHighestPowerOfTwo(pixData);
1008
1097
 
1009
1098
  // Source texture data from the PBO.
@@ -1012,7 +1101,7 @@ function vtkOpenGLTexture(publicAPI, model) {
1012
1101
 
1013
1102
  // openGLDataType
1014
1103
 
1015
- if (useTexStorage(dataType)) {
1104
+ if (useTexStorage(dataTypeToUse)) {
1016
1105
  model.context.texStorage3D(model.target, 1, model.internalFormat, model.width, model.height, model.depth);
1017
1106
  if (scaledData[0] != null) {
1018
1107
  model.context.texSubImage3D(model.target, 0, 0, 0, 0, model.width, model.height, model.depth, model.format, model.openGLDataType, scaledData[0]);
@@ -1023,7 +1112,7 @@ function vtkOpenGLTexture(publicAPI, model) {
1023
1112
  if (model.generateMipmap) {
1024
1113
  model.context.generateMipmap(model.target);
1025
1114
  }
1026
- model.allocatedGPUMemoryInBytes = model.width * model.height * model.depth * model.components * model._openGLRenderWindow.getDefaultTextureByteSize(dataType, model.oglNorm16Ext, model.useHalfFloat);
1115
+ model.allocatedGPUMemoryInBytes = model.width * model.height * model.depth * model.components * model._openGLRenderWindow.getDefaultTextureByteSize(dataTypeToUse, model.oglNorm16Ext, publicAPI.useHalfFloat());
1027
1116
  publicAPI.deactivate();
1028
1117
  return true;
1029
1118
  };
@@ -1050,7 +1139,6 @@ function vtkOpenGLTexture(publicAPI, model) {
1050
1139
  data,
1051
1140
  scaleOffsets
1052
1141
  } = processDataArray(dataArray, preferSizeOverAccuracy);
1053
- const numPixelsIn = width * height * depth;
1054
1142
  const offset = [];
1055
1143
  const scale = [];
1056
1144
  for (let c = 0; c < numComps; ++c) {
@@ -1076,46 +1164,13 @@ function vtkOpenGLTexture(publicAPI, model) {
1076
1164
  // Create a copy of scale and offset to avoid aliasing issues
1077
1165
  // Original is read only, copy is read/write
1078
1166
  // Use the copy as volumeInfo.scale and volumeInfo.offset
1079
- const scaleOffsetsCopy = structuredClone(scaleOffsets);
1080
1167
 
1081
1168
  // WebGL2 path, we have 3d textures etc
1082
1169
  if (model._openGLRenderWindow.getWebgl2()) {
1083
- if (model.oglNorm16Ext && !model.useHalfFloat && dataType === VtkDataTypes.SHORT) {
1084
- for (let c = 0; c < numComps; ++c) {
1085
- model.volumeInfo.scale[c] = 32767.0;
1086
- }
1087
- return publicAPI.create3DFromRaw(width, height, depth, numComps, dataType, data);
1088
- }
1089
- if (model.oglNorm16Ext && !model.useHalfFloat && dataType === VtkDataTypes.UNSIGNED_SHORT) {
1090
- for (let c = 0; c < numComps; ++c) {
1091
- model.volumeInfo.scale[c] = 65535.0;
1092
- }
1093
- return publicAPI.create3DFromRaw(width, height, depth, numComps, dataType, data);
1094
- }
1095
- if (dataType === VtkDataTypes.FLOAT || model.useHalfFloat && (dataType === VtkDataTypes.SHORT || dataType === VtkDataTypes.UNSIGNED_SHORT)) {
1096
- return publicAPI.create3DFromRaw(width, height, depth, numComps, dataType, data);
1097
- }
1098
- if (dataType === VtkDataTypes.UNSIGNED_CHAR) {
1099
- for (let c = 0; c < numComps; ++c) {
1100
- model.volumeInfo.scale[c] = 255.0;
1101
- }
1102
- return publicAPI.create3DFromRaw(width, height, depth, numComps, dataType, data);
1103
- }
1104
- // otherwise convert to float
1105
- const newArray = new Float32Array(numPixelsIn * numComps);
1106
- // use computed scale and offset
1107
- model.volumeInfo.offset = scaleOffsetsCopy.offset;
1108
- model.volumeInfo.scale = scaleOffsetsCopy.scale;
1109
- let count = 0;
1110
- const scaleInverse = scaleOffsetsCopy.scale.map(s => 1 / s);
1111
- for (let i = 0; i < numPixelsIn; i++) {
1112
- for (let nc = 0; nc < numComps; nc++) {
1113
- newArray[count] = (data[count] - scaleOffsetsCopy.offset[nc]) * scaleInverse[nc];
1114
- count++;
1115
- }
1116
- }
1117
- return publicAPI.create3DFromRaw(width, height, depth, numComps, VtkDataTypes.FLOAT, newArray);
1170
+ return publicAPI.create3DFromRaw(width, height, depth, numComps, dataType, data);
1118
1171
  }
1172
+ const numPixelsIn = width * height * depth;
1173
+ const scaleOffsetsCopy = structuredClone(scaleOffsets);
1119
1174
 
1120
1175
  // not webgl2, deal with webgl1, no 3d textures
1121
1176
  // and maybe no float textures
@@ -1267,6 +1322,11 @@ function vtkOpenGLTexture(publicAPI, model) {
1267
1322
  }
1268
1323
  return -1;
1269
1324
  };
1325
+
1326
+ // set use half float
1327
+ publicAPI.enableUseHalfFloat = use => {
1328
+ model.enableUseHalfFloat = use;
1329
+ };
1270
1330
  }
1271
1331
 
1272
1332
  // ----------------------------------------------------------------------------
@@ -1299,13 +1359,12 @@ const DEFAULT_VALUES = {
1299
1359
  baseLevel: 0,
1300
1360
  maxLevel: 1000,
1301
1361
  generateMipmap: false,
1302
- // use half float by default, but it will get set
1303
- // to false if the context does not support it or
1304
- // the voxel intensity range is out of the accurate
1305
- // range of half float
1306
- useHalfFloat: true,
1307
1362
  oglNorm16Ext: null,
1308
- allocatedGPUMemoryInBytes: 0
1363
+ allocatedGPUMemoryInBytes: 0,
1364
+ // by default it is enabled
1365
+ enableUseHalfFloat: true,
1366
+ // but by default we don't know if we can use half float base on the data range
1367
+ canUseHalfFloat: false
1309
1368
  };
1310
1369
 
1311
1370
  // ----------------------------------------------------------------------------
@@ -15,6 +15,7 @@ import { Representation } from '../Core/Property/Constants.js';
15
15
  import { Wrap, Filter } from './Texture/Constants.js';
16
16
  import { InterpolationType, OpacityMode, ColorMixPreset } from '../Core/VolumeProperty/Constants.js';
17
17
  import { BlendMode } from '../Core/VolumeMapper/Constants.js';
18
+ import { getTransferFunctionHash, getImageDataHash } from './RenderWindow/resourceSharingHelper.js';
18
19
  import { v as vtkVolumeVS } from './glsl/vtkVolumeVS.glsl.js';
19
20
  import { v as vtkVolumeFS } from './glsl/vtkVolumeFS.glsl.js';
20
21
  import { registerOverride } from './ViewNodeFactory.js';
@@ -28,9 +29,6 @@ const {
28
29
  // helper methods
29
30
  // ----------------------------------------------------------------------------
30
31
 
31
- function computeFnToString(pwfun, useIComps, numberOfComponents) {
32
- return pwfun ? `${pwfun.getMTime()}-${useIComps}-${numberOfComponents}` : '0';
33
- }
34
32
  function getColorCodeFromPreset(colorMixPreset) {
35
33
  switch (colorMixPreset) {
36
34
  case ColorMixPreset.CUSTOM:
@@ -417,18 +415,23 @@ function vtkOpenGLVolumeMapper(publicAPI, model) {
417
415
  program.setUniformf('sampleDistance', publicAPI.getCurrentSampleDistance(ren));
418
416
  const volInfo = model.scalarTexture.getVolumeInfo();
419
417
  const ipScalarRange = model.renderable.getIpScalarRange();
420
- const minVals = [];
421
- const maxVals = [];
422
- for (let i = 0; i < 4; i++) {
423
- // convert iprange from 0-1 into data range values
424
- minVals[i] = ipScalarRange[0] * volInfo.dataComputedScale[i] + volInfo.dataComputedOffset[i];
425
- maxVals[i] = ipScalarRange[1] * volInfo.dataComputedScale[i] + volInfo.dataComputedOffset[i];
426
- // convert data ranges into texture values
427
- minVals[i] = (minVals[i] - volInfo.offset[i]) / volInfo.scale[i];
428
- maxVals[i] = (maxVals[i] - volInfo.offset[i]) / volInfo.scale[i];
429
- }
430
- program.setUniform4f('ipScalarRangeMin', minVals[0], minVals[1], minVals[2], minVals[3]);
431
- program.setUniform4f('ipScalarRangeMax', maxVals[0], maxVals[1], maxVals[2], maxVals[3]);
418
+
419
+ // In some situations, we might not have computed the scale and offset
420
+ // for the data range, or it might not be needed.
421
+ if (volInfo?.dataComputedScale?.length) {
422
+ const minVals = [];
423
+ const maxVals = [];
424
+ for (let i = 0; i < 4; i++) {
425
+ // convert iprange from 0-1 into data range values
426
+ minVals[i] = ipScalarRange[0] * volInfo.dataComputedScale[i] + volInfo.dataComputedOffset[i];
427
+ maxVals[i] = ipScalarRange[1] * volInfo.dataComputedScale[i] + volInfo.dataComputedOffset[i];
428
+ // convert data ranges into texture values
429
+ minVals[i] = (minVals[i] - volInfo.offset[i]) / volInfo.scale[i];
430
+ maxVals[i] = (maxVals[i] - volInfo.offset[i]) / volInfo.scale[i];
431
+ }
432
+ program.setUniform4f('ipScalarRangeMin', minVals[0], minVals[1], minVals[2], minVals[3]);
433
+ program.setUniform4f('ipScalarRangeMax', maxVals[0], maxVals[1], maxVals[2], maxVals[3]);
434
+ }
432
435
 
433
436
  // if we have a zbuffer texture then set it
434
437
  if (model.zBufferTexture !== null) {
@@ -1044,7 +1047,7 @@ function vtkOpenGLVolumeMapper(publicAPI, model) {
1044
1047
  const numIComps = useIndependentComps ? numComp : 1;
1045
1048
  const scalarOpacityFunc = vprop.getScalarOpacity();
1046
1049
  const opTex = model._openGLRenderWindow.getGraphicsResourceForObject(scalarOpacityFunc);
1047
- let toString = computeFnToString(scalarOpacityFunc, useIndependentComps, numIComps);
1050
+ let toString = getTransferFunctionHash(scalarOpacityFunc, useIndependentComps, numIComps);
1048
1051
  const reBuildOp = !opTex?.oglObject || opTex.hash !== toString;
1049
1052
  if (reBuildOp) {
1050
1053
  model.opacityTexture = vtkOpenGLTexture.newInstance();
@@ -1096,7 +1099,7 @@ function vtkOpenGLVolumeMapper(publicAPI, model) {
1096
1099
 
1097
1100
  // rebuild color tfun?
1098
1101
  const colorTransferFunc = vprop.getRGBTransferFunction();
1099
- toString = computeFnToString(colorTransferFunc, useIndependentComps, numIComps);
1102
+ toString = getTransferFunctionHash(colorTransferFunc, useIndependentComps, numIComps);
1100
1103
  const cTex = model._openGLRenderWindow.getGraphicsResourceForObject(colorTransferFunc);
1101
1104
  const reBuildC = !cTex?.oglObject?.getHandle() || cTex?.hash !== toString;
1102
1105
  if (reBuildC) {
@@ -1133,7 +1136,7 @@ function vtkOpenGLVolumeMapper(publicAPI, model) {
1133
1136
  publicAPI.updateLabelOutlineThicknessTexture(actor);
1134
1137
  const tex = model._openGLRenderWindow.getGraphicsResourceForObject(scalars);
1135
1138
  // rebuild the scalarTexture if the data has changed
1136
- toString = `${image.getMTime()}A${scalars.getMTime()}`;
1139
+ toString = getImageDataHash(image, scalars);
1137
1140
  const reBuildTex = !tex?.oglObject?.getHandle() || tex?.hash !== toString;
1138
1141
  if (reBuildTex) {
1139
1142
  model.scalarTexture = vtkOpenGLTexture.newInstance();
package/index.d.ts CHANGED
@@ -31,6 +31,7 @@
31
31
  /// <reference path="./Common/DataModel/EdgeLocator.d.ts" />
32
32
  /// <reference path="./Common/DataModel/ITKHelper.d.ts" />
33
33
  /// <reference path="./Common/DataModel/ImageData.d.ts" />
34
+ /// <reference path="./Common/DataModel/ImplicitFunction.d.ts" />
34
35
  /// <reference path="./Common/DataModel/IncrementalOctreeNode.d.ts" />
35
36
  /// <reference path="./Common/DataModel/IncrementalOctreePointLocator.d.ts" />
36
37
  /// <reference path="./Common/DataModel/KochanekSpline1D.d.ts" />
@@ -216,6 +217,7 @@
216
217
  /// <reference path="./Rendering/OpenGL/HardwareSelector/Constants.d.ts" />
217
218
  /// <reference path="./Rendering/OpenGL/HardwareSelector.d.ts" />
218
219
  /// <reference path="./Rendering/OpenGL/RenderWindow.d.ts" />
220
+ /// <reference path="./Rendering/OpenGL/RenderWindow/resourceSharingHelper.d.ts" />
219
221
  /// <reference path="./Rendering/OpenGL/Texture/Constants.d.ts" />
220
222
  /// <reference path="./Rendering/OpenGL/Texture.d.ts" />
221
223
  /// <reference path="./Rendering/SceneGraph/RenderPass.d.ts" />
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kitware/vtk.js",
3
- "version": "32.0.1",
3
+ "version": "32.1.1",
4
4
  "description": "Visualization Toolkit for the Web",
5
5
  "keywords": [
6
6
  "3d",