@kitware/vtk.js 33.0.0-beta.3 → 33.0.0-beta.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/BREAKING_CHANGES.md +2 -0
  2. package/Common/Core/DataArray.d.ts +17 -0
  3. package/Common/Core/DataArray.js +36 -0
  4. package/Rendering/Core/AbstractImageMapper.d.ts +81 -0
  5. package/Rendering/Core/AbstractImageMapper.js +5 -2
  6. package/Rendering/Core/AbstractPicker.d.ts +13 -13
  7. package/Rendering/Core/AbstractPicker.js +1 -1
  8. package/Rendering/Core/Actor2D.d.ts +22 -0
  9. package/Rendering/Core/Actor2D.js +1 -1
  10. package/Rendering/Core/CellPicker.js +4 -1
  11. package/Rendering/Core/ImageCPRMapper.js +5 -4
  12. package/Rendering/Core/ImageProperty.d.ts +20 -1
  13. package/Rendering/Core/ImageProperty.js +7 -5
  14. package/Rendering/Core/ImageResliceMapper.d.ts +1 -2
  15. package/Rendering/Core/ImageResliceMapper.js +5 -4
  16. package/Rendering/Core/Viewport.js +13 -3
  17. package/Rendering/Core/VolumeMapper.d.ts +70 -0
  18. package/Rendering/Core/VolumeMapper.js +10 -5
  19. package/Rendering/Core/VolumeProperty.d.ts +20 -1
  20. package/Rendering/Core/VolumeProperty.js +7 -5
  21. package/Rendering/Misc/SynchronizableRenderWindow/BehaviorManager/CameraSynchronizer.js +2 -2
  22. package/Rendering/OpenGL/Framebuffer.js +7 -1
  23. package/Rendering/OpenGL/ImageCPRMapper.js +59 -7
  24. package/Rendering/OpenGL/ImageMapper.js +71 -9
  25. package/Rendering/OpenGL/ImageResliceMapper.js +60 -9
  26. package/Rendering/OpenGL/OrderIndependentTranslucentPass.js +20 -3
  27. package/Rendering/OpenGL/PolyDataMapper.js +7 -1
  28. package/Rendering/OpenGL/Renderer.js +1 -1
  29. package/Rendering/OpenGL/SurfaceLIC/LineIntegralConvolution2D/pingpong.js +7 -1
  30. package/Rendering/OpenGL/SurfaceLIC/SurfaceLICInterface.js +20 -3
  31. package/Rendering/OpenGL/Texture.d.ts +131 -62
  32. package/Rendering/OpenGL/Texture.js +287 -48
  33. package/Rendering/OpenGL/VolumeMapper.js +70 -10
  34. package/Rendering/SceneGraph/ViewNode.js +12 -2
  35. package/Rendering/WebXR/RenderWindowHelper.js +9 -0
  36. package/Widgets/Core/WidgetManager.d.ts +12 -1
  37. package/Widgets/Representations/WidgetRepresentation.d.ts +1 -7
  38. package/Widgets/Widgets3D/ResliceCursorWidget.d.ts +1 -8
  39. package/macros.js +1 -1
  40. package/macros2.js +7 -2
  41. package/package.json +11 -11
@@ -1,3 +1,4 @@
1
+ import DeepEqual from 'fast-deep-equal';
1
2
  import Constants from './Texture/Constants.js';
2
3
  import HalfFloat from '../../Common/Core/HalfFloat.js';
3
4
  import { n as newInstance$1, o as obj, s as set, e as setGet, g as get, i as moveToProtected, a as newTypedArray, c as macro } from '../../macros2.js';
@@ -17,7 +18,8 @@ const {
17
18
  const {
18
19
  vtkDebugMacro,
19
20
  vtkErrorMacro,
20
- vtkWarningMacro
21
+ vtkWarningMacro,
22
+ requiredParam
21
23
  } = macro;
22
24
  const {
23
25
  toHalf
@@ -30,6 +32,16 @@ const {
30
32
  function vtkOpenGLTexture(publicAPI, model) {
31
33
  // Set our className
32
34
  model.classHierarchy.push('vtkOpenGLTexture');
35
+ function getTexParams() {
36
+ return {
37
+ internalFormat: model.internalFormat,
38
+ format: model.format,
39
+ openGLDataType: model.openGLDataType,
40
+ width: model.width,
41
+ height: model.height
42
+ };
43
+ }
44
+
33
45
  // Renders myself
34
46
  publicAPI.render = function () {
35
47
  let renWin = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
@@ -84,7 +96,14 @@ function vtkOpenGLTexture(publicAPI, model) {
84
96
  publicAPI.setMinificationFilter(Filter.LINEAR_MIPMAP_LINEAR);
85
97
  }
86
98
  const canvas = model.renderable.getCanvas();
87
- publicAPI.create2DFromRaw(canvas.width, canvas.height, 4, VtkDataTypes.UNSIGNED_CHAR, canvas, true);
99
+ publicAPI.create2DFromRaw({
100
+ width: canvas.width,
101
+ height: canvas.height,
102
+ numComps: 4,
103
+ dataType: VtkDataTypes.UNSIGNED_CHAR,
104
+ data: canvas,
105
+ flip: true
106
+ });
88
107
  publicAPI.activate();
89
108
  publicAPI.sendParameters();
90
109
  model.textureBuildTime.modified();
@@ -96,7 +115,14 @@ function vtkOpenGLTexture(publicAPI, model) {
96
115
  model.generateMipmap = true;
97
116
  publicAPI.setMinificationFilter(Filter.LINEAR_MIPMAP_LINEAR);
98
117
  }
99
- publicAPI.create2DFromRaw(jsid.width, jsid.height, 4, VtkDataTypes.UNSIGNED_CHAR, jsid.data, true);
118
+ publicAPI.create2DFromRaw({
119
+ width: jsid.width,
120
+ height: jsid.height,
121
+ numComps: 4,
122
+ dataType: VtkDataTypes.UNSIGNED_CHAR,
123
+ data: jsid.data,
124
+ flip: true
125
+ });
100
126
  publicAPI.activate();
101
127
  publicAPI.sendParameters();
102
128
  model.textureBuildTime.modified();
@@ -121,9 +147,21 @@ function vtkOpenGLTexture(publicAPI, model) {
121
147
  publicAPI.setMinificationFilter(Filter.LINEAR_MIPMAP_LINEAR);
122
148
  }
123
149
  if (data.length % 6 === 0) {
124
- publicAPI.createCubeFromRaw(ext[1] - ext[0] + 1, ext[3] - ext[2] + 1, inScalars.getNumberOfComponents(), inScalars.getDataType(), data);
150
+ publicAPI.createCubeFromRaw({
151
+ width: ext[1] - ext[0] + 1,
152
+ height: ext[3] - ext[2] + 1,
153
+ numComps: inScalars.getNumberOfComponents(),
154
+ dataType: inScalars.getDataType(),
155
+ data
156
+ });
125
157
  } else {
126
- publicAPI.create2DFromRaw(ext[1] - ext[0] + 1, ext[3] - ext[2] + 1, inScalars.getNumberOfComponents(), inScalars.getDataType(), inScalars.getData());
158
+ publicAPI.create2DFromRaw({
159
+ width: ext[1] - ext[0] + 1,
160
+ height: ext[3] - ext[2] + 1,
161
+ numComps: inScalars.getNumberOfComponents(),
162
+ dataType: inScalars.getDataType(),
163
+ data: inScalars.getData()
164
+ });
127
165
  }
128
166
  publicAPI.activate();
129
167
  publicAPI.sendParameters();
@@ -148,6 +186,7 @@ function vtkOpenGLTexture(publicAPI, model) {
148
186
  if (model.context && model.handle) {
149
187
  model.context.deleteTexture(model.handle);
150
188
  }
189
+ model._prevTexParams = null;
151
190
  model.handle = 0;
152
191
  model.numberOfDimensions = 0;
153
192
  model.target = 0;
@@ -209,6 +248,7 @@ function vtkOpenGLTexture(publicAPI, model) {
209
248
  rwin.activateTexture(publicAPI);
210
249
  rwin.deactivateTexture(publicAPI);
211
250
  model.context.deleteTexture(model.handle);
251
+ model._prevTexParams = null;
212
252
  model.handle = 0;
213
253
  model.numberOfDimensions = 0;
214
254
  model.target = 0;
@@ -353,6 +393,7 @@ function vtkOpenGLTexture(publicAPI, model) {
353
393
 
354
394
  //----------------------------------------------------------------------------
355
395
  publicAPI.resetFormatAndType = () => {
396
+ model._prevTexParams = null;
356
397
  model.format = 0;
357
398
  model.internalFormat = 0;
358
399
  model._forceInternalFormat = false;
@@ -499,6 +540,86 @@ function vtkOpenGLTexture(publicAPI, model) {
499
540
  }
500
541
  };
501
542
 
543
+ //----------------------------------------------------------------------------
544
+
545
+ /**
546
+ * Gets the extent's size.
547
+ * @param {Extent} extent
548
+ */
549
+ function getExtentSize(extent) {
550
+ const [xmin, xmax, ymin, ymax, zmin, zmax] = extent;
551
+ return [xmax - xmin + 1, ymax - ymin + 1, zmax - zmin + 1];
552
+ }
553
+
554
+ //----------------------------------------------------------------------------
555
+
556
+ /**
557
+ * Gets the number of pixels in the extent.
558
+ * @param {Extent} extent
559
+ */
560
+ function getExtentPixelCount(extent) {
561
+ const [sx, sy, sz] = getExtentSize(extent);
562
+ return sx * sy * sz;
563
+ }
564
+
565
+ //----------------------------------------------------------------------------
566
+
567
+ /**
568
+ * Reads a flattened extent from the image data and writes to the given output array.
569
+ *
570
+ * Assumes X varies the fastest and Z varies the slowest.
571
+ *
572
+ * @param {*} data
573
+ * @param {*} dataDims
574
+ * @param {Extent} extent
575
+ * @param {TypedArray} outArray
576
+ * @param {number} outOffset
577
+ * @returns
578
+ */
579
+ function readExtentIntoArray(data, dataDims, extent, outArray, outOffset) {
580
+ const [xmin, xmax, ymin, ymax, zmin, zmax] = extent;
581
+ const [dx, dy] = dataDims;
582
+ const sxy = dx * dy;
583
+ let writeOffset = outOffset;
584
+ for (let zi = zmin; zi <= zmax; zi++) {
585
+ const zOffset = zi * sxy;
586
+ for (let yi = ymin; yi <= ymax; yi++) {
587
+ const zyOffset = zOffset + yi * dx;
588
+ // explicit alternative to data.subarray,
589
+ // due to potential perf issues on v8
590
+ for (let readOffset = zyOffset + xmin, end = zyOffset + xmax; readOffset <= end; readOffset++, writeOffset++) {
591
+ outArray[writeOffset] = data[readOffset];
592
+ }
593
+ }
594
+ }
595
+ }
596
+
597
+ //----------------------------------------------------------------------------
598
+
599
+ /**
600
+ * Reads several image extents into a contiguous pixel array.
601
+ *
602
+ * @param {*} data
603
+ * @param {Extent[]} extent
604
+ * @param {TypedArrayConstructor} typedArrayConstructor optional typed array constructor
605
+ * @returns
606
+ */
607
+ function readExtents(data, extents) {
608
+ let typedArrayConstructor = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
609
+ const constructor = typedArrayConstructor || data.constructor;
610
+ const numPixels = extents.reduce((count, extent) => count + getExtentPixelCount(extent), 0);
611
+ const extentPixels = new constructor(numPixels);
612
+ const dataDims = [model.width, model.height, model.depth];
613
+ let writeOffset = 0;
614
+ extents.forEach(extent => {
615
+ readExtentIntoArray(data, dataDims, extent, extentPixels, writeOffset);
616
+ writeOffset += getExtentPixelCount(extent);
617
+ });
618
+ return extentPixels;
619
+ }
620
+
621
+ //----------------------------------------------------------------------------
622
+
502
623
  /**
503
624
  * Updates the data array to match the required data type for OpenGL.
504
625
  *
@@ -508,23 +629,30 @@ function vtkOpenGLTexture(publicAPI, model) {
508
629
  * @param {string} dataType - The original data type of the input data.
509
630
  * @param {Array} data - The input data array that needs to be updated.
510
631
  * @param {boolean} [depth=false] - Indicates whether the data is a 3D array.
632
+ * @param {Array<Extent>} imageExtents only consider these image extents (default: [])
511
633
  * @returns {Array} The updated data array that matches the OpenGL data type.
512
634
  */
513
635
  publicAPI.updateArrayDataTypeForGL = function (dataType, data) {
514
636
  let depth = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
637
+ let imageExtents = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
515
638
  const pixData = [];
516
639
  let pixCount = model.width * model.height * model.components;
517
640
  if (depth) {
518
641
  pixCount *= model.depth;
519
642
  }
643
+ const onlyUpdateExtents = !!imageExtents.length;
520
644
 
521
645
  // if the opengl data type is float
522
646
  // then the data array must be float
523
647
  if (dataType !== VtkDataTypes.FLOAT && model.openGLDataType === model.context.FLOAT) {
524
648
  for (let idx = 0; idx < data.length; idx++) {
525
649
  if (data[idx]) {
526
- const dataArrayToCopy = data[idx].length > pixCount ? data[idx].subarray(0, pixCount) : data[idx];
527
- pixData.push(new Float32Array(dataArrayToCopy));
650
+ if (onlyUpdateExtents) {
651
+ pixData.push(readExtents(data[idx], imageExtents, Float32Array));
652
+ } else {
653
+ const dataArrayToCopy = data[idx].length > pixCount ? data[idx].subarray(0, pixCount) : data[idx];
654
+ pixData.push(new Float32Array(dataArrayToCopy));
655
+ }
528
656
  } else {
529
657
  pixData.push(null);
530
658
  }
@@ -536,8 +664,12 @@ function vtkOpenGLTexture(publicAPI, model) {
536
664
  if (dataType !== VtkDataTypes.UNSIGNED_CHAR && model.openGLDataType === model.context.UNSIGNED_BYTE) {
537
665
  for (let idx = 0; idx < data.length; idx++) {
538
666
  if (data[idx]) {
539
- const dataArrayToCopy = data[idx].length > pixCount ? data[idx].subarray(0, pixCount) : data[idx];
540
- pixData.push(new Uint8Array(dataArrayToCopy));
667
+ if (onlyUpdateExtents) {
668
+ pixData.push(readExtents(data[idx], imageExtents, Uint8Array));
669
+ } else {
670
+ const dataArrayToCopy = data[idx].length > pixCount ? data[idx].subarray(0, pixCount) : data[idx];
671
+ pixData.push(new Uint8Array(dataArrayToCopy));
672
+ }
541
673
  } else {
542
674
  pixData.push(null);
543
675
  }
@@ -556,9 +688,10 @@ function vtkOpenGLTexture(publicAPI, model) {
556
688
  if (halfFloat) {
557
689
  for (let idx = 0; idx < data.length; idx++) {
558
690
  if (data[idx]) {
559
- const newArray = new Uint16Array(pixCount);
560
- const src = data[idx];
561
- for (let i = 0; i < pixCount; i++) {
691
+ const src = onlyUpdateExtents ? readExtents(data[idx], imageExtents) : data[idx];
692
+ const newArray = new Uint16Array(onlyUpdateExtents ? src.length : pixCount);
693
+ const newArrayLen = newArray.length;
694
+ for (let i = 0; i < newArrayLen; i++) {
562
695
  newArray[i] = toHalf(src[i]);
563
696
  }
564
697
  pixData.push(newArray);
@@ -571,7 +704,7 @@ function vtkOpenGLTexture(publicAPI, model) {
571
704
  // The output has to be filled
572
705
  if (pixData.length === 0) {
573
706
  for (let i = 0; i < data.length; i++) {
574
- pixData.push(data[i]);
707
+ pixData.push(onlyUpdateExtents && data[i] ? readExtents(data[i], imageExtents) : data[i]);
575
708
  }
576
709
  }
577
710
  return pixData;
@@ -680,8 +813,16 @@ function vtkOpenGLTexture(publicAPI, model) {
680
813
  }
681
814
 
682
815
  //----------------------------------------------------------------------------
683
- publicAPI.create2DFromRaw = function (width, height, numComps, dataType, data) {
684
- let flip = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false;
816
+
817
+ publicAPI.create2DFromRaw = function () {
818
+ let {
819
+ width = requiredParam('width'),
820
+ height = requiredParam('height'),
821
+ numComps = requiredParam('numComps'),
822
+ dataType = requiredParam('dataType'),
823
+ data = requiredParam('data'),
824
+ flip = false
825
+ } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
685
826
  // Now determine the texture parameters using the arguments.
686
827
  publicAPI.getOpenGLDataType(dataType, true);
687
828
  publicAPI.getInternalFormat(dataType, numComps);
@@ -730,7 +871,14 @@ function vtkOpenGLTexture(publicAPI, model) {
730
871
  };
731
872
 
732
873
  //----------------------------------------------------------------------------
733
- publicAPI.createCubeFromRaw = (width, height, numComps, dataType, data) => {
874
+ publicAPI.createCubeFromRaw = function () {
875
+ let {
876
+ width = requiredParam('width'),
877
+ height = requiredParam('height'),
878
+ numComps = requiredParam('numComps'),
879
+ dataType = requiredParam('dataType'),
880
+ data = requiredParam('data')
881
+ } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
734
882
  // Now determine the texture parameters using the arguments.
735
883
  publicAPI.getOpenGLDataType(dataType);
736
884
  publicAPI.getInternalFormat(dataType, numComps);
@@ -811,7 +959,13 @@ function vtkOpenGLTexture(publicAPI, model) {
811
959
  };
812
960
 
813
961
  //----------------------------------------------------------------------------
814
- publicAPI.createDepthFromRaw = (width, height, dataType, data) => {
962
+ publicAPI.createDepthFromRaw = function () {
963
+ let {
964
+ width = requiredParam('width'),
965
+ height = requiredParam('height'),
966
+ dataType = requiredParam('dataType'),
967
+ data = requiredParam('data')
968
+ } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
815
969
  // Now determine the texture parameters using the arguments.
816
970
  publicAPI.getOpenGLDataType(dataType);
817
971
  model.format = model.context.DEPTH_COMPONENT;
@@ -984,22 +1138,47 @@ function vtkOpenGLTexture(publicAPI, model) {
984
1138
  scaleOffsets
985
1139
  };
986
1140
  }
987
- publicAPI.create2DFilterableFromRaw = function (width, height, numberOfComponents, dataType, values) {
988
- let preferSizeOverAccuracy = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false;
989
- return publicAPI.create2DFilterableFromDataArray(width, height, vtkDataArray.newInstance({
990
- numberOfComponents,
991
- dataType,
992
- values
993
- }), preferSizeOverAccuracy);
1141
+ publicAPI.create2DFilterableFromRaw = function () {
1142
+ let {
1143
+ width = requiredParam('width'),
1144
+ height = requiredParam('height'),
1145
+ numComps = requiredParam('numComps'),
1146
+ dataType = requiredParam('dataType'),
1147
+ data = requiredParam('data'),
1148
+ preferSizeOverAccuracy = false,
1149
+ ranges = undefined
1150
+ } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1151
+ return publicAPI.create2DFilterableFromDataArray({
1152
+ width,
1153
+ height,
1154
+ dataArray: vtkDataArray.newInstance({
1155
+ numComps,
1156
+ dataType,
1157
+ values: data,
1158
+ ranges
1159
+ }),
1160
+ preferSizeOverAccuracy
1161
+ });
994
1162
  };
995
- publicAPI.create2DFilterableFromDataArray = function (width, height, dataArray) {
996
- let preferSizeOverAccuracy = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
1163
+ publicAPI.create2DFilterableFromDataArray = function () {
1164
+ let {
1165
+ width = requiredParam('width'),
1166
+ height = requiredParam('height'),
1167
+ dataArray = requiredParam('dataArray'),
1168
+ preferSizeOverAccuracy = false
1169
+ } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
997
1170
  const {
998
1171
  numComps,
999
1172
  dataType,
1000
1173
  data
1001
1174
  } = processDataArray(dataArray, preferSizeOverAccuracy);
1002
- publicAPI.create2DFromRaw(width, height, numComps, dataType, data);
1175
+ publicAPI.create2DFromRaw({
1176
+ width,
1177
+ height,
1178
+ numComps,
1179
+ dataType,
1180
+ data
1181
+ });
1003
1182
  };
1004
1183
  publicAPI.updateVolumeInfoForGL = (dataType, numComps) => {
1005
1184
  let isScalingApplied = false;
@@ -1054,7 +1233,16 @@ function vtkOpenGLTexture(publicAPI, model) {
1054
1233
  };
1055
1234
 
1056
1235
  //----------------------------------------------------------------------------
1057
- publicAPI.create3DFromRaw = (width, height, depth, numComps, dataType, data) => {
1236
+ publicAPI.create3DFromRaw = function () {
1237
+ let {
1238
+ width = requiredParam('width'),
1239
+ height = requiredParam('height'),
1240
+ depth = requiredParam('depth'),
1241
+ numComps = requiredParam('numComps'),
1242
+ dataType = requiredParam('dataType'),
1243
+ data = requiredParam('data'),
1244
+ updatedExtents = []
1245
+ } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1058
1246
  let dataTypeToUse = dataType;
1059
1247
  let dataToUse = data;
1060
1248
  if (!publicAPI.updateVolumeInfoForGL(dataTypeToUse, numComps) && dataToUse) {
@@ -1096,25 +1284,42 @@ function vtkOpenGLTexture(publicAPI, model) {
1096
1284
  model._openGLRenderWindow.activateTexture(publicAPI);
1097
1285
  publicAPI.createTexture();
1098
1286
  publicAPI.bind();
1287
+ const hasUpdatedExtents = updatedExtents.length > 0;
1288
+
1289
+ // It's possible for the texture parameters to change while
1290
+ // streaming, so check for such a change.
1291
+ const rebuildEntireTexture = !hasUpdatedExtents || !DeepEqual(model._prevTexParams, getTexParams());
1292
+
1099
1293
  // Create an array of texture with one texture
1100
1294
  const dataArray = [dataToUse];
1101
1295
  const is3DArray = true;
1102
- const pixData = publicAPI.updateArrayDataTypeForGL(dataTypeToUse, dataArray, is3DArray);
1296
+ const pixData = publicAPI.updateArrayDataTypeForGL(dataTypeToUse, dataArray, is3DArray, rebuildEntireTexture ? [] : updatedExtents);
1103
1297
  const scaledData = scaleTextureToHighestPowerOfTwo(pixData);
1104
1298
 
1105
1299
  // Source texture data from the PBO.
1106
1300
  // model.context.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
1107
1301
  model.context.pixelStorei(model.context.UNPACK_ALIGNMENT, 1);
1108
-
1109
- // openGLDataType
1110
-
1111
- if (useTexStorage(dataTypeToUse)) {
1112
- model.context.texStorage3D(model.target, 1, model.internalFormat, model.width, model.height, model.depth);
1113
- if (scaledData[0] != null) {
1114
- model.context.texSubImage3D(model.target, 0, 0, 0, 0, model.width, model.height, model.depth, model.format, model.openGLDataType, scaledData[0]);
1302
+ if (rebuildEntireTexture) {
1303
+ if (useTexStorage(dataTypeToUse)) {
1304
+ model.context.texStorage3D(model.target, 1, model.internalFormat, model.width, model.height, model.depth);
1305
+ if (scaledData[0] != null) {
1306
+ model.context.texSubImage3D(model.target, 0, 0, 0, 0, model.width, model.height, model.depth, model.format, model.openGLDataType, scaledData[0]);
1307
+ }
1308
+ } else {
1309
+ model.context.texImage3D(model.target, 0, model.internalFormat, model.width, model.height, model.depth, 0, model.format, model.openGLDataType, scaledData[0]);
1310
+ }
1311
+ model._prevTexParams = getTexParams();
1312
+ } else if (hasUpdatedExtents) {
1313
+ const extentPixels = scaledData[0];
1314
+ let readOffset = 0;
1315
+ for (let i = 0; i < updatedExtents.length; i++) {
1316
+ const extent = updatedExtents[i];
1317
+ const extentSize = getExtentSize(extent);
1318
+ const extentPixelCount = getExtentPixelCount(extent);
1319
+ const textureData = new extentPixels.constructor(extentPixels.buffer, readOffset, extentPixelCount);
1320
+ readOffset += textureData.byteLength;
1321
+ model.context.texSubImage3D(model.target, 0, extent[0], extent[2], extent[4], extentSize[0], extentSize[1], extentSize[2], model.format, model.openGLDataType, textureData);
1115
1322
  }
1116
- } else {
1117
- model.context.texImage3D(model.target, 0, model.internalFormat, model.width, model.height, model.depth, 0, model.format, model.openGLDataType, scaledData[0]);
1118
1323
  }
1119
1324
  if (model.generateMipmap) {
1120
1325
  model.context.generateMipmap(model.target);
@@ -1127,19 +1332,44 @@ function vtkOpenGLTexture(publicAPI, model) {
1127
1332
  //----------------------------------------------------------------------------
1128
1333
  // This method simulates a 3D texture using 2D
1129
1334
  // Prefer create3DFilterableFromDataArray to enable caching of min and max values
1130
- publicAPI.create3DFilterableFromRaw = function (width, height, depth, numberOfComponents, dataType, values) {
1131
- let preferSizeOverAccuracy = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : false;
1132
- return publicAPI.create3DFilterableFromDataArray(width, height, depth, vtkDataArray.newInstance({
1133
- numberOfComponents,
1134
- dataType,
1135
- values
1136
- }), preferSizeOverAccuracy);
1335
+ publicAPI.create3DFilterableFromRaw = function () {
1336
+ let {
1337
+ width = requiredParam('width'),
1338
+ height = requiredParam('height'),
1339
+ depth = requiredParam('depth'),
1340
+ numComps = requiredParam('numComps'),
1341
+ dataType = requiredParam('dataType'),
1342
+ data = requiredParam('data'),
1343
+ preferSizeOverAccuracy = false,
1344
+ ranges = undefined,
1345
+ updatedExtents = []
1346
+ } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1347
+ return publicAPI.create3DFilterableFromDataArray({
1348
+ width,
1349
+ height,
1350
+ depth,
1351
+ dataArray: vtkDataArray.newInstance({
1352
+ numComps,
1353
+ dataType,
1354
+ values: data,
1355
+ ranges
1356
+ }),
1357
+ preferSizeOverAccuracy,
1358
+ updatedExtents
1359
+ });
1137
1360
  };
1138
1361
 
1139
1362
  //----------------------------------------------------------------------------
1140
1363
  // This method create a 3D texture from dimensions and a DataArray
1141
- publicAPI.create3DFilterableFromDataArray = function (width, height, depth, dataArray) {
1142
- let preferSizeOverAccuracy = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
1364
+ publicAPI.create3DFilterableFromDataArray = function () {
1365
+ let {
1366
+ width = requiredParam('width'),
1367
+ height = requiredParam('height'),
1368
+ depth = requiredParam('depth'),
1369
+ dataArray = requiredParam('dataArray'),
1370
+ preferSizeOverAccuracy = false,
1371
+ updatedExtents = []
1372
+ } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1143
1373
  const {
1144
1374
  numComps,
1145
1375
  dataType,
@@ -1174,7 +1404,15 @@ function vtkOpenGLTexture(publicAPI, model) {
1174
1404
 
1175
1405
  // WebGL2 path, we have 3d textures etc
1176
1406
  if (model._openGLRenderWindow.getWebgl2()) {
1177
- return publicAPI.create3DFromRaw(width, height, depth, numComps, dataType, data);
1407
+ return publicAPI.create3DFromRaw({
1408
+ width,
1409
+ height,
1410
+ depth,
1411
+ numComps,
1412
+ dataType,
1413
+ data,
1414
+ updatedExtents
1415
+ });
1178
1416
  }
1179
1417
  const numPixelsIn = width * height * depth;
1180
1418
  const scaleOffsetsCopy = structuredClone(scaleOffsets);
@@ -1343,6 +1581,7 @@ function vtkOpenGLTexture(publicAPI, model) {
1343
1581
  const DEFAULT_VALUES = {
1344
1582
  _openGLRenderWindow: null,
1345
1583
  _forceInternalFormat: false,
1584
+ _prevTexParams: null,
1346
1585
  context: null,
1347
1586
  handle: 0,
1348
1587
  sendParametersTime: null,
@@ -1013,7 +1013,13 @@ function vtkOpenGLVolumeMapper(publicAPI, model) {
1013
1013
  }
1014
1014
  model.jitterTexture.setMinificationFilter(Filter.NEAREST);
1015
1015
  model.jitterTexture.setMagnificationFilter(Filter.NEAREST);
1016
- model.jitterTexture.create2DFromRaw(32, 32, 1, VtkDataTypes.FLOAT, jitterArray);
1016
+ model.jitterTexture.create2DFromRaw({
1017
+ width: 32,
1018
+ height: 32,
1019
+ numComps: 1,
1020
+ dataType: VtkDataTypes.FLOAT,
1021
+ data: jitterArray
1022
+ });
1017
1023
  }
1018
1024
  const volumeProperties = actor.getProperties();
1019
1025
  const firstValidInput = model.currentValidInputs[0];
@@ -1034,7 +1040,10 @@ function vtkOpenGLVolumeMapper(publicAPI, model) {
1034
1040
  if (reBuildOp) {
1035
1041
  const newOpacityTexture = vtkOpenGLTexture.newInstance();
1036
1042
  newOpacityTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
1037
- const oWidth = 1024;
1043
+ let oWidth = model.renderable.getOpacityTextureWidth();
1044
+ if (oWidth <= 0) {
1045
+ oWidth = model.context.getParameter(model.context.MAX_TEXTURE_SIZE);
1046
+ }
1038
1047
  const oSize = oWidth * 2 * numIComps;
1039
1048
  const ofTable = new Float32Array(oSize);
1040
1049
  const tmpTable = new Float32Array(oWidth);
@@ -1058,13 +1067,25 @@ function vtkOpenGLVolumeMapper(publicAPI, model) {
1058
1067
  // visible artifacts. High values of opacity quickly terminate without
1059
1068
  // artifacts.
1060
1069
  if (model._openGLRenderWindow.getWebgl2() || model.context.getExtension('OES_texture_float') && model.context.getExtension('OES_texture_float_linear')) {
1061
- newOpacityTexture.create2DFromRaw(oWidth, 2 * numIComps, 1, VtkDataTypes.FLOAT, ofTable);
1070
+ newOpacityTexture.create2DFromRaw({
1071
+ width: oWidth,
1072
+ height: 2 * numIComps,
1073
+ numComps: 1,
1074
+ dataType: VtkDataTypes.FLOAT,
1075
+ data: ofTable
1076
+ });
1062
1077
  } else {
1063
1078
  const oTable = new Uint8ClampedArray(oSize);
1064
1079
  for (let i = 0; i < oSize; ++i) {
1065
1080
  oTable[i] = 255.0 * ofTable[i];
1066
1081
  }
1067
- newOpacityTexture.create2DFromRaw(oWidth, 2 * numIComps, 1, VtkDataTypes.UNSIGNED_CHAR, oTable);
1082
+ newOpacityTexture.create2DFromRaw({
1083
+ width: oWidth,
1084
+ height: 2 * numIComps,
1085
+ numComps: 1,
1086
+ dataType: VtkDataTypes.UNSIGNED_CHAR,
1087
+ data: oTable
1088
+ });
1068
1089
  }
1069
1090
  if (firstScalarOpacityFunc) {
1070
1091
  model._openGLRenderWindow.setGraphicsResourceForObject(firstScalarOpacityFunc, newOpacityTexture, opacityFuncHash);
@@ -1088,7 +1109,10 @@ function vtkOpenGLVolumeMapper(publicAPI, model) {
1088
1109
  if (reBuildC) {
1089
1110
  const newColorTexture = vtkOpenGLTexture.newInstance();
1090
1111
  newColorTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
1091
- const cWidth = 1024;
1112
+ let cWidth = model.renderable.getColorTextureWidth();
1113
+ if (cWidth <= 0) {
1114
+ cWidth = model.context.getParameter(model.context.MAX_TEXTURE_SIZE);
1115
+ }
1092
1116
  const cSize = cWidth * 2 * numIComps * 3;
1093
1117
  const cTable = new Uint8ClampedArray(cSize);
1094
1118
  const tmpTable = new Float32Array(cWidth * 3);
@@ -1104,7 +1128,13 @@ function vtkOpenGLVolumeMapper(publicAPI, model) {
1104
1128
  newColorTexture.resetFormatAndType();
1105
1129
  newColorTexture.setMinificationFilter(Filter.LINEAR);
1106
1130
  newColorTexture.setMagnificationFilter(Filter.LINEAR);
1107
- newColorTexture.create2DFromRaw(cWidth, 2 * numIComps, 3, VtkDataTypes.UNSIGNED_CHAR, cTable);
1131
+ newColorTexture.create2DFromRaw({
1132
+ width: cWidth,
1133
+ height: 2 * numIComps,
1134
+ numComps: 3,
1135
+ dataType: VtkDataTypes.UNSIGNED_CHAR,
1136
+ data: cTable
1137
+ });
1108
1138
  model._openGLRenderWindow.setGraphicsResourceForObject(firstColorTransferFunc, newColorTexture, colorFuncHash);
1109
1139
  model.colorTexture = newColorTexture;
1110
1140
  } else {
@@ -1125,7 +1155,9 @@ function vtkOpenGLVolumeMapper(publicAPI, model) {
1125
1155
  const tex = model._openGLRenderWindow.getGraphicsResourceForObject(scalars);
1126
1156
  const scalarsHash = getImageDataHash(imageData, scalars);
1127
1157
  const reBuildTex = !tex?.oglObject?.getHandle() || tex?.hash !== scalarsHash;
1128
- if (reBuildTex) {
1158
+ const updatedExtents = volumeProperty.getUpdatedExtents();
1159
+ const hasUpdatedExtents = !!updatedExtents.length;
1160
+ if (reBuildTex && !hasUpdatedExtents) {
1129
1161
  const newScalarTexture = vtkOpenGLTexture.newInstance();
1130
1162
  newScalarTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
1131
1163
  // Build the textures
@@ -1133,12 +1165,31 @@ function vtkOpenGLVolumeMapper(publicAPI, model) {
1133
1165
  // Use norm16 for scalar texture if the extension is available
1134
1166
  newScalarTexture.setOglNorm16Ext(model.context.getExtension('EXT_texture_norm16'));
1135
1167
  newScalarTexture.resetFormatAndType();
1136
- newScalarTexture.create3DFilterableFromDataArray(dims[0], dims[1], dims[2], scalars, volumeProperty.getPreferSizeOverAccuracy());
1168
+ newScalarTexture.create3DFilterableFromDataArray({
1169
+ width: dims[0],
1170
+ height: dims[1],
1171
+ depth: dims[2],
1172
+ dataArray: scalars,
1173
+ preferSizeOverAccuracy: volumeProperty.getPreferSizeOverAccuracy()
1174
+ });
1137
1175
  model._openGLRenderWindow.setGraphicsResourceForObject(scalars, newScalarTexture, scalarsHash);
1138
1176
  model.scalarTextures[component] = newScalarTexture;
1139
1177
  } else {
1140
1178
  model.scalarTextures[component] = tex.oglObject;
1141
1179
  }
1180
+ if (hasUpdatedExtents) {
1181
+ // If hasUpdatedExtents, then the texture is partially updated.
1182
+ // clear the array to acknowledge the update.
1183
+ volumeProperty.setUpdatedExtents([]);
1184
+ const dims = imageData.getDimensions();
1185
+ model.scalarTextures[component].create3DFilterableFromDataArray({
1186
+ width: dims[0],
1187
+ height: dims[1],
1188
+ depth: dims[2],
1189
+ dataArray: scalars,
1190
+ updatedExtents
1191
+ });
1192
+ }
1142
1193
  replaceGraphicsResource(model._openGLRenderWindow, model._scalarTexturesCore[component], scalars);
1143
1194
  model._scalarTexturesCore[component] = scalars;
1144
1195
  });
@@ -1151,7 +1202,10 @@ function vtkOpenGLVolumeMapper(publicAPI, model) {
1151
1202
  if (reBuildL) {
1152
1203
  const newLabelOutlineThicknessTexture = vtkOpenGLTexture.newInstance();
1153
1204
  newLabelOutlineThicknessTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
1154
- const lWidth = 1024;
1205
+ let lWidth = model.renderable.getLabelOutlineTextureWidth();
1206
+ if (lWidth <= 0) {
1207
+ lWidth = model.context.getParameter(model.context.MAX_TEXTURE_SIZE);
1208
+ }
1155
1209
  const lHeight = 1;
1156
1210
  const lSize = lWidth * lHeight;
1157
1211
  const lTable = new Uint8Array(lSize);
@@ -1168,7 +1222,13 @@ function vtkOpenGLVolumeMapper(publicAPI, model) {
1168
1222
  newLabelOutlineThicknessTexture.setMagnificationFilter(Filter.NEAREST);
1169
1223
 
1170
1224
  // Create a 2D texture (acting as 1D) from the raw data
1171
- newLabelOutlineThicknessTexture.create2DFromRaw(lWidth, lHeight, 1, VtkDataTypes.UNSIGNED_CHAR, lTable);
1225
+ newLabelOutlineThicknessTexture.create2DFromRaw({
1226
+ width: lWidth,
1227
+ height: lHeight,
1228
+ numComps: 1,
1229
+ dataType: VtkDataTypes.UNSIGNED_CHAR,
1230
+ data: lTable
1231
+ });
1172
1232
  if (labelOutlineThicknessArray) {
1173
1233
  model._openGLRenderWindow.setGraphicsResourceForObject(labelOutlineThicknessArray, newLabelOutlineThicknessTexture, labelOutlineThicknessHash);
1174
1234
  }