@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.
- package/BREAKING_CHANGES.md +2 -0
- package/Common/Core/DataArray.d.ts +17 -0
- package/Common/Core/DataArray.js +36 -0
- package/Rendering/Core/AbstractImageMapper.d.ts +81 -0
- package/Rendering/Core/AbstractImageMapper.js +5 -2
- package/Rendering/Core/AbstractPicker.d.ts +13 -13
- package/Rendering/Core/AbstractPicker.js +1 -1
- package/Rendering/Core/Actor2D.d.ts +22 -0
- package/Rendering/Core/Actor2D.js +1 -1
- package/Rendering/Core/CellPicker.js +4 -1
- package/Rendering/Core/ImageCPRMapper.js +5 -4
- package/Rendering/Core/ImageProperty.d.ts +20 -1
- package/Rendering/Core/ImageProperty.js +7 -5
- package/Rendering/Core/ImageResliceMapper.d.ts +1 -2
- package/Rendering/Core/ImageResliceMapper.js +5 -4
- package/Rendering/Core/Viewport.js +13 -3
- package/Rendering/Core/VolumeMapper.d.ts +70 -0
- package/Rendering/Core/VolumeMapper.js +10 -5
- package/Rendering/Core/VolumeProperty.d.ts +20 -1
- package/Rendering/Core/VolumeProperty.js +7 -5
- package/Rendering/Misc/SynchronizableRenderWindow/BehaviorManager/CameraSynchronizer.js +2 -2
- package/Rendering/OpenGL/Framebuffer.js +7 -1
- package/Rendering/OpenGL/ImageCPRMapper.js +59 -7
- package/Rendering/OpenGL/ImageMapper.js +71 -9
- package/Rendering/OpenGL/ImageResliceMapper.js +60 -9
- package/Rendering/OpenGL/OrderIndependentTranslucentPass.js +20 -3
- package/Rendering/OpenGL/PolyDataMapper.js +7 -1
- package/Rendering/OpenGL/Renderer.js +1 -1
- package/Rendering/OpenGL/SurfaceLIC/LineIntegralConvolution2D/pingpong.js +7 -1
- package/Rendering/OpenGL/SurfaceLIC/SurfaceLICInterface.js +20 -3
- package/Rendering/OpenGL/Texture.d.ts +131 -62
- package/Rendering/OpenGL/Texture.js +287 -48
- package/Rendering/OpenGL/VolumeMapper.js +70 -10
- package/Rendering/SceneGraph/ViewNode.js +12 -2
- package/Rendering/WebXR/RenderWindowHelper.js +9 -0
- package/Widgets/Core/WidgetManager.d.ts +12 -1
- package/Widgets/Representations/WidgetRepresentation.d.ts +1 -7
- package/Widgets/Widgets3D/ResliceCursorWidget.d.ts +1 -8
- package/macros.js +1 -1
- package/macros2.js +7 -2
- 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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
527
|
-
|
|
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
|
-
|
|
540
|
-
|
|
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
|
|
560
|
-
const
|
|
561
|
-
|
|
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
|
-
|
|
684
|
-
|
|
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 = (
|
|
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 = (
|
|
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 (
|
|
988
|
-
let
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
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 (
|
|
996
|
-
let
|
|
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(
|
|
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 = (
|
|
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
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
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 (
|
|
1131
|
-
let
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
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 (
|
|
1142
|
-
let
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
}
|