@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.
- package/Common/DataModel/Box.d.ts +2 -1
- package/Common/DataModel/Box.js +2 -1
- package/Common/DataModel/Cone.d.ts +2 -6
- package/Common/DataModel/Cone.js +2 -1
- package/Common/DataModel/Cylinder.d.ts +3 -2
- package/Common/DataModel/Cylinder.js +2 -1
- package/Common/DataModel/ImageData.d.ts +0 -1
- package/Common/DataModel/ImageData.js +2 -2
- package/Common/DataModel/ImplicitBoolean.js +5 -4
- package/Common/DataModel/ImplicitFunction.d.ts +68 -0
- package/Common/DataModel/ImplicitFunction.js +60 -0
- package/Common/DataModel/Plane.d.ts +2 -1
- package/Common/DataModel/Plane.js +2 -1
- package/Common/DataModel/Sphere.d.ts +10 -17
- package/Common/DataModel/Sphere.js +11 -19
- package/Rendering/OpenGL/ImageCPRMapper.js +90 -66
- package/Rendering/OpenGL/ImageMapper.js +3 -9
- package/Rendering/OpenGL/ImageResliceMapper.js +9 -17
- package/Rendering/OpenGL/RenderWindow/resourceSharingHelper.d.ts +34 -0
- package/Rendering/OpenGL/RenderWindow/resourceSharingHelper.js +14 -0
- package/Rendering/OpenGL/Texture.d.ts +26 -0
- package/Rendering/OpenGL/Texture.js +132 -73
- package/Rendering/OpenGL/VolumeMapper.js +21 -18
- package/index.d.ts +2 -0
- package/package.json +1 -1
|
@@ -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,
|
|
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 && !
|
|
367
|
+
case model.oglNorm16Ext && !useHalfFloat && VtkDataTypes.SHORT:
|
|
366
368
|
return model.context.SHORT;
|
|
367
|
-
case model.oglNorm16Ext && !
|
|
369
|
+
case model.oglNorm16Ext && !useHalfFloat && VtkDataTypes.UNSIGNED_SHORT:
|
|
368
370
|
return model.context.UNSIGNED_SHORT;
|
|
369
371
|
// use half float type
|
|
370
|
-
case
|
|
372
|
+
case useHalfFloat && VtkDataTypes.SHORT:
|
|
371
373
|
return model.context.HALF_FLOAT;
|
|
372
|
-
case
|
|
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
|
-
|
|
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 =
|
|
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,
|
|
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 =
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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 (!
|
|
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(
|
|
1074
|
+
publicAPI.getOpenGLDataType(dataTypeToUse);
|
|
986
1075
|
|
|
987
1076
|
// Now determine the texture parameters using the arguments.
|
|
988
|
-
publicAPI.getInternalFormat(
|
|
989
|
-
publicAPI.getFormat(
|
|
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 = [
|
|
1093
|
+
const dataArray = [dataToUse];
|
|
1005
1094
|
const is3DArray = true;
|
|
1006
|
-
const pixData =
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
421
|
-
|
|
422
|
-
for
|
|
423
|
-
|
|
424
|
-
minVals
|
|
425
|
-
maxVals
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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" />
|