@kitware/vtk.js 19.3.0 → 19.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Helper class to convert to/from half float
3
+ */
4
+
5
+ /**
6
+ * Convert a number to half float representation
7
+ * @param {number} input
8
+ * @return encoded half float number (16 bits)
9
+ */
10
+ export function toHalf(input: number): number;
11
+
12
+ /**
13
+ * Convert a half float representation to a number
14
+ * @param {number} input
15
+ * @return decoded half float number
16
+ */
17
+ export function fromHalf(input: number): number;
18
+
19
+ export declare const HalfFloat: {
20
+ toHalf: typeof toHalf;
21
+ fromHalf: typeof fromHalf;
22
+ }
23
+
24
+ export default HalfFloat;
@@ -0,0 +1,80 @@
1
+ /* eslint-disable no-bitwise */
2
+ var floatView = new Float32Array(1);
3
+ var int32View = new Int32Array(floatView.buffer);
4
+ /* eslint-disable no-bitwise */
5
+
6
+ /* This method is faster than the OpenEXR implementation (very often
7
+ * used, eg. in Ogre), with the additional benefit of rounding, inspired
8
+ * by James Tursa?s half-precision code. */
9
+
10
+ function toHalf(val) {
11
+ floatView[0] = val;
12
+ var x = int32View[0];
13
+ var bits = x >> 16 & 0x8000;
14
+ /* Get the sign */
15
+
16
+ var m = x >> 12 & 0x07ff;
17
+ /* Keep one extra bit for rounding */
18
+
19
+ var e = x >> 23 & 0xff;
20
+ /* Using int is faster here */
21
+
22
+ /* If zero, or denormal, or exponent underflows too much for a denormal
23
+ * half, return signed zero. */
24
+
25
+ if (e < 103) {
26
+ return bits;
27
+ }
28
+ /* If NaN, return NaN. If Inf or exponent overflow, return Inf. */
29
+
30
+
31
+ if (e > 142) {
32
+ bits |= 0x7c00;
33
+ /* If exponent was 0xff and one mantissa bit was set, it means NaN,
34
+ * not Inf, so make sure we set one mantissa bit too. */
35
+
36
+ bits |= (e === 255 ? 0 : 1) && x & 0x007fffff;
37
+ return bits;
38
+ }
39
+ /* If exponent underflows but not too much, return a denormal */
40
+
41
+
42
+ if (e < 113) {
43
+ m |= 0x0800;
44
+ /* Extra rounding may overflow and set mantissa to 0 and exponent
45
+ * to 1, which is OK. */
46
+
47
+ bits |= (m >> 114 - e) + (m >> 113 - e & 1);
48
+ return bits;
49
+ }
50
+
51
+ bits |= e - 112 << 10 | m >> 1;
52
+ /* Extra rounding. An overflow will set mantissa to 0 and increment
53
+ * the exponent, which is OK. */
54
+
55
+ bits += m & 1;
56
+ return bits;
57
+ }
58
+
59
+ function fromHalf(h) {
60
+ var s = (h & 0x8000) >> 15;
61
+ var e = (h & 0x7c00) >> 10;
62
+ var f = h & 0x03ff;
63
+
64
+ if (e === 0) {
65
+ return (s ? -1 : 1) * Math.pow(2, -14) * (f / Math.pow(2, 10));
66
+ }
67
+
68
+ if (e === 0x1f) {
69
+ return f ? NaN : (s ? -1 : 1) * Infinity;
70
+ }
71
+
72
+ return (s ? -1 : 1) * Math.pow(2, e - 15) * (1 + f / Math.pow(2, 10));
73
+ }
74
+
75
+ var HalfFloat = {
76
+ fromHalf: fromHalf,
77
+ toHalf: toHalf
78
+ };
79
+
80
+ export { HalfFloat as default };
package/Common/Core.js CHANGED
@@ -2,6 +2,7 @@ import Base64 from './Core/Base64.js';
2
2
  import vtkCellArray from './Core/CellArray.js';
3
3
  import vtkDataArray from './Core/DataArray.js';
4
4
  import Endian from './Core/Endian.js';
5
+ import HalfFloat from './Core/HalfFloat.js';
5
6
  import ImageHelper from './Core/ImageHelper.js';
6
7
  import vtkLookupTable from './Core/LookupTable.js';
7
8
  import { v as vtkMath } from './Core/Math/index.js';
@@ -18,6 +19,7 @@ var Core = {
18
19
  vtkCellArray: vtkCellArray,
19
20
  vtkDataArray: vtkDataArray,
20
21
  vtkEndian: Endian,
22
+ vtkHalfFloat: HalfFloat,
21
23
  vtkImageHelper: ImageHelper,
22
24
  vtkLookupTable: vtkLookupTable,
23
25
  vtkMath: vtkMath,
package/README.md CHANGED
@@ -48,7 +48,7 @@ In general VTK tries to be as portable as possible; the specific configurations
48
48
 
49
49
  vtk.js supports the following development environments:
50
50
 
51
- - Node 10+
51
+ - Node 12+
52
52
  - NPM 6+
53
53
 
54
54
  and we use [@babel/preset-env](https://www.npmjs.com/package/@babel/preset-env) with the [defaults](https://github.com/Kitware/vtk-js/blob/master/.browserslistrc) set of [browsers target](https://browserl.ist/?q=defaults).
@@ -1,4 +1,5 @@
1
1
  import macro from '../../macros.js';
2
+ import HalfFloat from '../../Common/Core/HalfFloat.js';
2
3
  import vtkWebGPUBufferManager from './BufferManager.js';
3
4
  import vtkWebGPUTextureView from './TextureView.js';
4
5
  import vtkWebGPUTypes from './Types.js';
@@ -79,20 +80,28 @@ function vtkWebGPUTexture(publicAPI, model) {
79
80
  // the data here before passing to the buffer. e.g. if it is unorm8x4 then
80
81
  // we need to have width be a multiple of 64
81
82
 
82
- var currWidthInBytes = model.width * tDetails.stride;
83
+ var currWidthInBytes = model.width * tDetails.stride; // is this a half float texture?
83
84
 
84
- if (currWidthInBytes % 256) {
85
- var oArray = req.nativeArray;
85
+ var halfFloat = tDetails.elementSize === 2 && tDetails.sampleType === 'float'; // if we need to copy the data
86
+
87
+ if (halfFloat || currWidthInBytes % 256) {
88
+ var inArray = req.nativeArray;
86
89
  var bufferWidthInBytes = 256 * Math.floor((currWidthInBytes + 255) / 256);
87
- var bufferWidth = bufferWidthInBytes / oArray.BYTES_PER_ELEMENT;
88
- var oWidth = currWidthInBytes / oArray.BYTES_PER_ELEMENT;
89
- var nArray = macro.newTypedArray(oArray.name, bufferWidth * model.height * model.depth);
90
+ var bufferWidth = bufferWidthInBytes / tDetails.elementSize;
91
+ var inWidth = currWidthInBytes / inArray.BYTES_PER_ELEMENT;
92
+ var outArray = macro.newTypedArray(halfFloat ? 'Uint16Array' : inArray.name, bufferWidth * model.height * model.depth);
90
93
 
91
94
  for (var v = 0; v < model.height * model.depth; v++) {
92
- nArray.set(oArray.subarray(v * oWidth, (v + 1) * oWidth), v * bufferWidth);
95
+ if (halfFloat) {
96
+ for (var i = 0; i < inWidth; i++) {
97
+ outArray[v * bufferWidth + i] = HalfFloat.toHalf(inArray[v * inWidth + i]);
98
+ }
99
+ } else {
100
+ outArray.set(inArray.subarray(v * inWidth, (v + 1) * inWidth), v * bufferWidth);
101
+ }
93
102
  }
94
103
 
95
- buffRequest.nativeArray = nArray;
104
+ buffRequest.nativeArray = outArray;
96
105
  bufferBytesPerRow = bufferWidthInBytes;
97
106
  }
98
107
 
@@ -58,6 +58,8 @@ function vtkWebGPUTextureManager(publicAPI, model) {
58
58
  case VtkDataTypes.UNSIGNED_CHAR:
59
59
  req.format += '8unorm';
60
60
  break;
61
+ // todo extend to other types that are not filterable
62
+ // as they can be useful
61
63
 
62
64
  case VtkDataTypes.FLOAT:
63
65
  case VtkDataTypes.UNSIGNED_INT:
@@ -66,7 +68,8 @@ function vtkWebGPUTextureManager(publicAPI, model) {
66
68
  case VtkDataTypes.UNSIGNED_SHORT:
67
69
  case VtkDataTypes.SHORT:
68
70
  default:
69
- console.log('unsupported data type in texture');
71
+ req.format += '16float';
72
+ break;
70
73
  }
71
74
  } // fill in values based on image if the request has it
72
75
 
@@ -5,6 +5,7 @@ import vtkWebGPUUniformBuffer from './UniformBuffer.js';
5
5
  import vtkWebGPUShaderCache from './ShaderCache.js';
6
6
  import vtkWebGPUStorageBuffer from './StorageBuffer.js';
7
7
  import vtkWebGPUSampler from './Sampler.js';
8
+ import vtkWebGPUTypes from './Types.js';
8
9
  import { BlendMode } from '../Core/VolumeMapper/Constants.js';
9
10
  import { i as identity, t as translate, j as transpose, g as invert, m as multiply, s as scale } from '../../vendor/gl-matrix/esm/mat4.js';
10
11
 
@@ -240,8 +241,7 @@ function vtkWebGPUVolumePassFSQ(publicAPI, model) {
240
241
 
241
242
  var modelToIndex = _image3.getWorldToIndex();
242
243
 
243
- transpose(tmp2Mat4, modelToIndex);
244
- multiply(tmpMat4, tmp2Mat4, tmpMat4); // tmpMat4 is now SC -> Index
244
+ multiply(tmpMat4, modelToIndex, tmpMat4); // tmpMat4 is now SC -> Index
245
245
 
246
246
  var dims = _image3.getDimensions();
247
247
 
@@ -301,13 +301,23 @@ function vtkWebGPUVolumePassFSQ(publicAPI, model) {
301
301
 
302
302
  var numComp = scalars.getNumberOfComponents();
303
303
  var iComps = vprop.getIndependentComponents(); // const numIComps = iComps ? numComp : 1;
304
+ // half float
304
305
 
306
+ var tformat = model.textureViews[_vidx2 + 4].getTexture().getFormat();
307
+
308
+ var tDetails = vtkWebGPUTypes.getDetailsFromTextureFormat(tformat);
309
+ var halfFloat = tDetails.elementSize === 2 && tDetails.sampleType === 'float';
305
310
  var volInfo = {
306
311
  scale: [255.0],
307
312
  offset: [0.0]
308
- }; // three levels of shift scale combined into one
313
+ };
314
+
315
+ if (halfFloat) {
316
+ volInfo.scale[0] = 1.0;
317
+ } // three levels of shift scale combined into one
309
318
  // for performance in the fragment shader
310
319
 
320
+
311
321
  for (var compIdx = 0; compIdx < numComp; compIdx++) {
312
322
  var target = iComps ? compIdx : 0;
313
323
  var sscale = volInfo.scale[compIdx];
@@ -381,10 +391,8 @@ function vtkWebGPUVolumePassFSQ(publicAPI, model) {
381
391
  model.sampleDist = sampleDist;
382
392
  model.UBO.setValue('SampleDistance', sampleDist);
383
393
  model.UBO.sendIfNeeded(device);
384
- }
394
+ } // add in 3d volume textures
385
395
 
386
- publicAPI.updateLUTImage(device);
387
- publicAPI.updateSSBO(device); // add in 3d volume textures
388
396
 
389
397
  for (var vidx = 0; vidx < model.volumes.length; vidx++) {
390
398
  var webgpuvol = model.volumes[vidx];
@@ -406,6 +414,9 @@ function vtkWebGPUVolumePassFSQ(publicAPI, model) {
406
414
  model.textureViews[vidx + 4] = tview;
407
415
  }
408
416
  }
417
+
418
+ publicAPI.updateLUTImage(device);
419
+ publicAPI.updateSSBO(device);
409
420
  };
410
421
 
411
422
  publicAPI.computePipelineHash = function () {