@kitware/vtk.js 22.3.0 → 22.5.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.
@@ -74,7 +74,14 @@ function fetchArray(instance, baseURL, array) {
74
74
 
75
75
  if (array.ref && !array.ref.pending) {
76
76
  return new Promise(function (resolve, reject) {
77
- var url = [baseURL, array.ref.basepath, options.compression ? "".concat(array.ref.id, ".gz") : array.ref.id].join('/');
77
+ var url = null;
78
+
79
+ if (array.ref.url) {
80
+ url = array.ref.url;
81
+ } else {
82
+ url = [baseURL, array.ref.basepath, options.compression ? "".concat(array.ref.id, ".gz") : array.ref.id].join('/');
83
+ }
84
+
78
85
  var xhr = openAsyncXHR('GET', url, options);
79
86
 
80
87
  xhr.onreadystatechange = function (e) {
@@ -1,5 +1,5 @@
1
- import _defineProperty from '@babel/runtime/helpers/defineProperty';
2
1
  import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
2
+ import _defineProperty from '@babel/runtime/helpers/defineProperty';
3
3
  import { vec3, mat4 } from 'gl-matrix';
4
4
  import * as d3 from 'd3-scale';
5
5
  import { K as nearestPowerOfTwo } from '../../Common/Core/Math/index.js';
@@ -8,7 +8,6 @@ import vtkActor from './Actor.js';
8
8
  import vtkDataArray from '../../Common/Core/DataArray.js';
9
9
  import vtkScalarsToColors from '../../Common/Core/ScalarsToColors.js';
10
10
  import vtkMapper from './Mapper.js';
11
- import vtkPixelSpaceCallbackMapper from './PixelSpaceCallbackMapper.js';
12
11
  import vtkPolyData from '../../Common/DataModel/PolyData.js';
13
12
  import vtkTexture from './Texture.js';
14
13
 
@@ -19,6 +18,16 @@ var VectorMode = vtkScalarsToColors.VectorMode; // -----------------------------
19
18
  // vtkScalarBarActor
20
19
  //
21
20
  // Note log scales are currently not supported
21
+ //
22
+ // Developer note: This class is broken into the main class and a helper
23
+ // class. The main class holds view independent properties (those properties
24
+ // that do not change as the view's resolution/aspect ratio change). The
25
+ // helper class is instantiated one per view and holds properties that can
26
+ // depend on view specific values such as resolution. The helper class code
27
+ // could have been left to the View specific implementation (such as
28
+ // vtkWebGPUScalarBarActor) but is instead placed here to it can be shared by
29
+ // multiple rendering backends.
30
+ //
22
31
  // ----------------------------------------------------------------------------
23
32
  // some shared temp variables to reduce heap allocs
24
33
 
@@ -38,10 +47,9 @@ function applyTextStyle(ctx, style) {
38
47
  } // ----------------------------------------------------------------------------
39
48
  // Default autoLayout function
40
49
  // ----------------------------------------------------------------------------
41
- // compute good values to use based on window size etc
42
- // a bunch of heuristics here with hand tuned constants
43
- // These values worked for me but really this method
44
- // could be redically changed. The basic gist is
50
+ // compute good values to use based on window size etc a bunch of heuristics
51
+ // here with hand tuned constants These values worked for me but really this
52
+ // method could be redically changed. The basic gist is
45
53
  // 1) compute a resonable font size
46
54
  // 2) render the text atlas using those font sizes
47
55
  // 3) pick horizontal or vertical bsed on window size
@@ -49,96 +57,151 @@ function applyTextStyle(ctx, style) {
49
57
  // compute the box size and position such that
50
58
  // the text will all fit nicely and the bar will be a resonable size
51
59
  // 5) compute the bar segments based on the above settings
60
+ //
61
+ // Note that this function can and should read values from the
62
+ // ScalarBarActor but should only write values to the view dependent helper
63
+ // instance that is provided as those values are the ones that will be used
64
+ // for rendering.
65
+ //
52
66
 
53
67
 
54
68
  function defaultAutoLayout(publicAPI, model) {
55
- return function () {
69
+ return function (helper) {
56
70
  // we don't do a linear scale, the proportions for
57
71
  // a 700 pixel window differ from a 1400
58
- var xAxisAdjust = Math.pow(model.lastSize[0] / 700, 0.8);
59
- var yAxisAdjust = Math.pow(model.lastSize[1] / 700, 0.8);
60
- var minAdjust = Math.min(xAxisAdjust, yAxisAdjust); // compute a reasonable font size first
61
-
62
- model.axisTextStyle.fontSize = Math.max(24 * minAdjust, 12);
63
-
64
- if (model.lastAspectRatio > 1.0) {
65
- model.tickTextStyle.fontSize = Math.max(20 * minAdjust, 10);
72
+ var lastSize = helper.getLastSize();
73
+ var xAxisAdjust = Math.pow(lastSize[0] / 700, 0.8);
74
+ var yAxisAdjust = Math.pow(lastSize[1] / 700, 0.8);
75
+ var minAdjust = Math.min(xAxisAdjust, yAxisAdjust);
76
+ var axisTextStyle = helper.getAxisTextStyle();
77
+ var tickTextStyle = helper.getTickTextStyle();
78
+ Object.assign(axisTextStyle, model.axisTextStyle);
79
+ Object.assign(tickTextStyle, model.tickTextStyle); // compute a reasonable font size first
80
+
81
+ axisTextStyle.fontSize = Math.max(24 * minAdjust, 12);
82
+
83
+ if (helper.getLastAspectRatio() > 1.0) {
84
+ tickTextStyle.fontSize = Math.max(20 * minAdjust, 10);
66
85
  } else {
67
- model.tickTextStyle.fontSize = Math.max(16 * minAdjust, 10);
86
+ tickTextStyle.fontSize = Math.max(16 * minAdjust, 10);
68
87
  } // rebuild the text atlas
69
88
 
70
89
 
71
- var textSizes = publicAPI.updateTextureAtlas(); // now compute the boxSize and pixel offsets, different algorithm
90
+ var textSizes = helper.updateTextureAtlas(); // now compute the boxSize and pixel offsets, different algorithm
72
91
  // for horizonal versus vertical
73
92
 
74
- model.topTitle = false; // if vertical
93
+ helper.setTopTitle(false);
94
+ var boxSize = helper.getBoxSizeByReference(); // if vertical
75
95
 
76
- if (model.lastAspectRatio > 1.0) {
77
- model.tickLabelPixelOffset = 0.4 * model.tickTextStyle.fontSize;
78
- var tickWidth = 2.0 * (textSizes.tickWidth + model.tickLabelPixelOffset) / model.lastSize[0];
79
- model.axisTitlePixelOffset = 0.8 * model.axisTextStyle.fontSize; // width required if the title is vertical
96
+ if (helper.getLastAspectRatio() > 1.0) {
97
+ helper.setTickLabelPixelOffset(0.4 * tickTextStyle.fontSize);
98
+ var tickWidth = 2.0 * (textSizes.tickWidth + helper.getTickLabelPixelOffset()) / lastSize[0];
99
+ helper.setAxisTitlePixelOffset(0.8 * axisTextStyle.fontSize); // width required if the title is vertical
80
100
 
81
- var titleWidth = 2.0 * (textSizes.titleHeight + model.axisTitlePixelOffset) / model.lastSize[0]; // if the title will fit within the width of the bar then that looks
82
- // nicer to put it at the top (model.topTitle), otherwise rotate it
101
+ var titleWidth = 2.0 * (textSizes.titleHeight + helper.getAxisTitlePixelOffset()) / lastSize[0]; // if the title will fit within the width of the bar then that looks
102
+ // nicer to put it at the top (helper.topTitle), otherwise rotate it
83
103
  // and place it sideways
84
104
 
85
- if (tickWidth + 0.4 * titleWidth > 2.0 * textSizes.titleWidth / model.lastSize[0]) {
86
- model.topTitle = true;
87
- model.boxSize[0] = tickWidth + 0.4 * titleWidth;
88
- model.boxPosition = [0.98 - model.boxSize[0], -0.92];
105
+ if (tickWidth + 0.4 * titleWidth > 2.0 * textSizes.titleWidth / lastSize[0]) {
106
+ helper.setTopTitle(true);
107
+ boxSize[0] = tickWidth + 0.4 * titleWidth;
108
+ helper.setBoxPosition([0.98 - boxSize[0], -0.92]);
89
109
  } else {
90
- model.boxSize[0] = tickWidth + 1.4 * titleWidth;
91
- model.boxPosition = [0.99 - model.boxSize[0], -0.92];
110
+ boxSize[0] = tickWidth + 1.4 * titleWidth;
111
+ helper.setBoxPosition([0.99 - boxSize[0], -0.92]);
92
112
  }
93
113
 
94
- model.boxSize[1] = Math.max(1.2, Math.min(1.84 / yAxisAdjust, 1.84));
114
+ boxSize[1] = Math.max(1.2, Math.min(1.84 / yAxisAdjust, 1.84));
95
115
  } else {
96
116
  // horizontal
97
- model.axisTitlePixelOffset = 2.0 * model.tickTextStyle.fontSize;
98
- model.tickLabelPixelOffset = 0.5 * model.tickTextStyle.fontSize;
99
- var tickHeight = 2.0 * (textSizes.tickHeight + model.tickLabelPixelOffset) / model.lastSize[1];
100
- var titleHeight = 2.0 * (textSizes.titleHeight + model.axisTitlePixelOffset) / model.lastSize[1];
117
+ helper.setAxisTitlePixelOffset(2.0 * tickTextStyle.fontSize);
118
+ helper.setTickLabelPixelOffset(0.5 * tickTextStyle.fontSize);
119
+ var tickHeight = 2.0 * (textSizes.tickHeight + helper.getTickLabelPixelOffset()) / lastSize[1];
120
+ var titleHeight = 2.0 * (textSizes.titleHeight + helper.getAxisTitlePixelOffset()) / lastSize[1];
101
121
 
102
- var _tickWidth = 2.0 * textSizes.tickWidth / model.lastSize[0];
122
+ var _tickWidth = 2.0 * textSizes.tickWidth / lastSize[0];
103
123
 
104
- model.boxSize[0] = Math.min(1.9, Math.max(1.4, 1.4 * _tickWidth * (model.ticks.length + 3)));
105
- model.boxSize[1] = tickHeight + titleHeight;
106
- model.boxPosition = [-0.5 * model.boxSize[0], -0.97];
124
+ boxSize[0] = Math.min(1.9, Math.max(1.4, 1.4 * _tickWidth * (helper.getTicks().length + 3)));
125
+ boxSize[1] = tickHeight + titleHeight;
126
+ helper.setBoxPosition([-0.5 * boxSize[0], -0.97]);
107
127
  } // recomute bar segments based on positioning
108
128
 
109
129
 
110
- publicAPI.recomputeBarSegments(textSizes);
130
+ helper.recomputeBarSegments(textSizes);
111
131
  };
112
- }
132
+ } // many properties of this actor depend on the API specific view The main
133
+ // dependency being the resolution as that drives what font sizes to use.
134
+ // Bacause of this we need to do some of the calculations in a API specific
135
+ // subclass. But... we don't want a lot of duplicated code between WebGL and
136
+ // WebGPU for example so we have this helper class, that is designed to be
137
+ // fairly API independent so that API specific views can call this to do
138
+ // most of the work.
113
139
 
114
- function vtkScalarBarActor(publicAPI, model) {
140
+
141
+ function vtkScalarBarActorHelper(publicAPI, model) {
115
142
  // Set our className
116
- model.classHierarchy.push('vtkScalarBarActor'); // main method to rebuild the scalarBar when something has changed
117
- // tracks modified times
143
+ model.classHierarchy.push('vtkScalarBarActorHelper');
144
+
145
+ publicAPI.setRenderable = function (renderable) {
146
+ if (model.renderable === renderable) {
147
+ return;
148
+ }
118
149
 
119
- publicAPI.update = function () {
120
- if (!model.scalarsToColors || !model.visibility) {
150
+ model.renderable = renderable;
151
+ model.barActor.setProperty(renderable.getProperty());
152
+ model.barActor.setParentProp(renderable);
153
+ model.tmActor.setProperty(renderable.getProperty());
154
+ model.tmActor.setParentProp(renderable);
155
+ model.axisTextStyle = _objectSpread({}, renderable.getAxisTextStyle());
156
+ model.tickTextStyle = _objectSpread({}, renderable.getTickTextStyle());
157
+ publicAPI.modified();
158
+ };
159
+
160
+ publicAPI.updateAPISpecificData = function (size, camera, renderWindow) {
161
+ // has the size changed?
162
+ if (model.lastSize[0] !== size[0] || model.lastSize[1] !== size[1]) {
163
+ model.lastSize[0] = size[0];
164
+ model.lastSize[1] = size[1];
165
+ model.lastAspectRatio = size[0] / size[1];
166
+ model.forceUpdate = true;
167
+ }
168
+
169
+ var scalarsToColors = model.renderable.getScalarsToColors();
170
+
171
+ if (!scalarsToColors || !model.renderable.getVisibility()) {
121
172
  return;
122
173
  } // make sure the lut is assigned to our mapper
123
174
 
124
175
 
125
- model.barMapper.setLookupTable(model.scalarsToColors); // did something significant change? If so rebuild a lot of things
176
+ model.barMapper.setLookupTable(scalarsToColors); // camera should be the same for all views
126
177
 
127
- if (model.forceUpdate || Math.max(model.scalarsToColors.getMTime(), publicAPI.getMTime()) > model.lastRebuildTime.getMTime()) {
128
- var range = model.scalarsToColors.getMappingRange();
178
+ model.camera = camera;
179
+ model.renderWindow = renderWindow; // did something significant change? If so rebuild a lot of things
180
+
181
+ if (model.forceUpdate || Math.max(scalarsToColors.getMTime(), publicAPI.getMTime()) > model.lastRebuildTime.getMTime()) {
182
+ var range = scalarsToColors.getMappingRange();
129
183
  model.lastTickBounds = _toConsumableArray(range);
130
184
  model.barMapper.setScalarRange(model.lastTickBounds); // compute tick marks for axes (update for log scale)
131
185
 
132
186
  var scale = d3.scaleLinear().domain([model.lastTickBounds[0], model.lastTickBounds[1]]);
133
187
  model.ticks = scale.ticks(5);
134
188
  var format = scale.tickFormat(5);
135
- model.tickStrings = model.ticks.map(format);
189
+ model.tickstrings = model.ticks.map(format);
136
190
 
137
- if (model.automated) {
138
- model.autoLayout();
191
+ if (model.renderable.getAutomated()) {
192
+ model.renderable.getAutoLayout()(publicAPI);
139
193
  } else {
140
- // rebuild the texture only when force or changed bounds, face
194
+ // copy values from renderable
195
+ model.axisTextStyle = _objectSpread({}, model.renderable.getAxisTextStyle());
196
+ model.tickTextStyle = _objectSpread({}, model.renderable.getTickTextStyle());
197
+ model.barPosition = _toConsumableArray(model.renderable.getBarPosition());
198
+ model.barSize = _toConsumableArray(model.renderable.getBarSize());
199
+ model.boxPosition = _toConsumableArray(model.renderable.getBoxPosition());
200
+ model.boxSize = _toConsumableArray(model.renderable.getBoxSize());
201
+ model.axisTitlePixelOffset = model.renderable.getAxisTitlePixelOffset();
202
+ model.tickLabelPixelOffset = model.renderable.getTickLabelPixelOffset(); // rebuild the texture only when force or changed bounds, face
141
203
  // visibility changes do to change the atlas
204
+
142
205
  var textSizes = publicAPI.updateTextureAtlas(); // recompute bar segments based on positioning
143
206
 
144
207
  publicAPI.recomputeBarSegments(textSizes);
@@ -171,7 +234,7 @@ function vtkScalarBarActor(publicAPI, model) {
171
234
 
172
235
  if (doUpdate) {
173
236
  model.forceViewUpdate = true;
174
- publicAPI.update();
237
+ model.renderWindow.render();
175
238
  }
176
239
  }
177
240
  }; // create the texture map atlas that contains the rendering of
@@ -191,14 +254,14 @@ function vtkScalarBarActor(publicAPI, model) {
191
254
  var totalHeight = 1; // start one pixel in so we have a border
192
255
 
193
256
  applyTextStyle(model.tmContext, model.axisTextStyle);
194
- var metrics = model.tmContext.measureText(model.axisLabel);
257
+ var metrics = model.tmContext.measureText(model.renderable.getAxisLabel());
195
258
  var entry = {
196
259
  height: metrics.actualBoundingBoxAscent + 2,
197
260
  startingHeight: totalHeight,
198
261
  width: metrics.width + 2,
199
262
  textStyle: model.axisTextStyle
200
263
  };
201
- newTmAtlas.set(model.axisLabel, entry);
264
+ newTmAtlas.set(model.renderable.getAxisLabel(), entry);
202
265
  totalHeight += entry.height;
203
266
  maxWidth = entry.width;
204
267
  results.titleWidth = entry.width;
@@ -207,7 +270,7 @@ function vtkScalarBarActor(publicAPI, model) {
207
270
  results.tickWidth = 0;
208
271
  results.tickHeight = 0;
209
272
  applyTextStyle(model.tmContext, model.tickTextStyle);
210
- var strings = [].concat(_toConsumableArray(model.tickStrings), ['NaN', 'Below', 'Above']);
273
+ var strings = [].concat(_toConsumableArray(model.tickstrings), ['NaN', 'Below', 'Above']);
211
274
 
212
275
  for (var t = 0; t < strings.length; t++) {
213
276
  if (!newTmAtlas.has(strings[t])) {
@@ -319,7 +382,7 @@ function vtkScalarBarActor(publicAPI, model) {
319
382
 
320
383
 
321
384
  publicAPI.recomputeBarSegments = function (textSizes) {
322
- var _model$scalarsToColor, _model$scalarsToColor2, _model$scalarsToColor3, _model$scalarsToColor4;
385
+ var _model$renderable$get, _model$renderable$get2, _model$renderable$get3, _model$renderable$get4;
323
386
 
324
387
  // first compute the barSize/Position
325
388
  var segSize = publicAPI.computeBarSize(textSizes);
@@ -339,22 +402,22 @@ function vtkScalarBarActor(publicAPI, model) {
339
402
  startPos[barAxis] += segSize[barAxis] + segSpace;
340
403
  }
341
404
 
342
- if (model.drawNanAnnotation && model.scalarsToColors.getNanColor) {
405
+ if (model.renderable.getDrawNanAnnotation() && model.renderable.getScalarsToColors().getNanColor()) {
343
406
  pushSeg('NaN', [NaN, NaN, NaN, NaN]);
344
407
  }
345
408
 
346
- if (model.drawBelowRangeSwatch && (_model$scalarsToColor = (_model$scalarsToColor2 = model.scalarsToColors).getUseBelowRangeColor) !== null && _model$scalarsToColor !== void 0 && _model$scalarsToColor.call(_model$scalarsToColor2)) {
409
+ if (model.renderable.getDrawBelowRangeSwatch() && (_model$renderable$get = (_model$renderable$get2 = model.renderable.getScalarsToColors()).getUseBelowRangeColor) !== null && _model$renderable$get !== void 0 && _model$renderable$get.call(_model$renderable$get2)) {
347
410
  pushSeg('Below', [-0.1, -0.1, -0.1, -0.1]);
348
411
  }
349
412
 
350
- var haveAbove = (_model$scalarsToColor3 = (_model$scalarsToColor4 = model.scalarsToColors).getUseAboveRangeColor) === null || _model$scalarsToColor3 === void 0 ? void 0 : _model$scalarsToColor3.call(_model$scalarsToColor4); // extra space around the ticks section
413
+ var haveAbove = (_model$renderable$get3 = (_model$renderable$get4 = model.renderable.getScalarsToColors()).getUseAboveRangeColor) === null || _model$renderable$get3 === void 0 ? void 0 : _model$renderable$get3.call(_model$renderable$get4); // extra space around the ticks section
351
414
 
352
415
  startPos[barAxis] += segSpace;
353
416
  var oldSegSize = segSize[barAxis];
354
417
  segSize[barAxis] = haveAbove ? 1.0 - 2.0 * segSpace - segSize[barAxis] - startPos[barAxis] : 1.0 - segSpace - startPos[barAxis];
355
418
  pushSeg('ticks', model.vertical ? [0, 0, 0.995, 0.995] : [0, 0.995, 0.995, 0]);
356
419
 
357
- if (model.drawAboveRangeSwatch && haveAbove) {
420
+ if (model.renderable.getDrawAboveRangeSwatch() && haveAbove) {
358
421
  segSize[barAxis] = oldSegSize;
359
422
  startPos[barAxis] += segSpace;
360
423
  pushSeg('Above', [1.1, 1.1, 1.1, 1.1]);
@@ -464,7 +527,7 @@ function vtkScalarBarActor(publicAPI, model) {
464
527
  } // update the polydata
465
528
 
466
529
 
467
- var numLabels = model.tickStrings.length + model.barSegments.length;
530
+ var numLabels = model.tickstrings.length + model.barSegments.length;
468
531
  var numPts = numLabels * 4;
469
532
  var numTris = numLabels * 2;
470
533
  var points = new Float64Array(numPts * 3);
@@ -489,14 +552,14 @@ function vtkScalarBarActor(publicAPI, model) {
489
552
  tmpv3[1] = model.barPosition[1] + model.barSize[1];
490
553
  vec3.transformMat4(ptv3, tmpv3, invmat); // write the axis label
491
554
 
492
- publicAPI.createPolyDataForOneLabel(model.axisLabel, ptv3, xDir, yDir, [0, 1], model.axisTitlePixelOffset, results);
555
+ publicAPI.createPolyDataForOneLabel(model.renderable.getAxisLabel(), ptv3, xDir, yDir, [0, 1], model.axisTitlePixelOffset, results);
493
556
  } else {
494
557
  tmpv3[0] = model.barPosition[0] + model.barSize[0];
495
558
  tmpv3[1] = model.barPosition[1] + 0.5 * model.barSize[1];
496
559
  vec3.transformMat4(ptv3, tmpv3, invmat); // write the axis label
497
560
 
498
561
  vec3.scale(xDir, xDir, -1);
499
- publicAPI.createPolyDataForOneLabel(model.axisLabel, ptv3, yDir, xDir, [0, -1], model.axisTitlePixelOffset, results);
562
+ publicAPI.createPolyDataForOneLabel(model.renderable.getAxisLabel(), ptv3, yDir, xDir, [0, -1], model.axisTitlePixelOffset, results);
500
563
  vec3.scale(xDir, xDir, -1);
501
564
  }
502
565
 
@@ -505,7 +568,7 @@ function vtkScalarBarActor(publicAPI, model) {
505
568
  tmpv3[0] = model.barPosition[0] + 0.5 * model.barSize[0];
506
569
  tmpv3[1] = model.barPosition[1] + model.barSize[1];
507
570
  vec3.transformMat4(ptv3, tmpv3, invmat);
508
- publicAPI.createPolyDataForOneLabel(model.axisLabel, ptv3, xDir, yDir, dir, model.axisTitlePixelOffset, results);
571
+ publicAPI.createPolyDataForOneLabel(model.renderable.getAxisLabel(), ptv3, xDir, yDir, dir, model.axisTitlePixelOffset, results);
509
572
  }
510
573
 
511
574
  tmp2v3[2] = -0.99; // near plane
@@ -536,7 +599,7 @@ function vtkScalarBarActor(publicAPI, model) {
536
599
  var tickPos = (model.ticks[t] - model.lastTickBounds[0]) / (model.lastTickBounds[1] - model.lastTickBounds[0]);
537
600
  tmp2v3[spacedAxis] = tickSegmentStart + tickSegmentSize * tickPos;
538
601
  vec3.transformMat4(ptv3, tmp2v3, invmat);
539
- publicAPI.createPolyDataForOneLabel(model.tickStrings[t], ptv3, xDir, yDir, dir, model.tickLabelPixelOffset, results);
602
+ publicAPI.createPolyDataForOneLabel(model.tickstrings[t], ptv3, xDir, yDir, dir, model.tickLabelPixelOffset, results);
540
603
  }
541
604
 
542
605
  var tcoordDA = vtkDataArray.newInstance({
@@ -553,22 +616,23 @@ function vtkScalarBarActor(publicAPI, model) {
553
616
  };
554
617
 
555
618
  publicAPI.updatePolyDataForBarSegments = function () {
556
- var _model$scalarsToColor5, _model$scalarsToColor6, _model$scalarsToColor7, _model$scalarsToColor8;
619
+ var _scalarsToColors$getU, _scalarsToColors$getU2;
557
620
 
558
621
  var cmat = model.camera.getCompositeProjectionMatrix(model.lastAspectRatio, -1, 1);
559
622
  mat4.transpose(cmat, cmat);
560
623
  mat4.invert(invmat, cmat);
624
+ var scalarsToColors = model.renderable.getScalarsToColors();
561
625
  var numberOfExtraColors = 0;
562
626
 
563
- if (model.drawNanAnnotation && model.scalarsToColors.getNanColor) {
627
+ if (model.renderable.getDrawNanAnnotation() && scalarsToColors.getNanColor()) {
564
628
  numberOfExtraColors += 1;
565
629
  }
566
630
 
567
- if (model.drawBelowRangeSwatch && (_model$scalarsToColor5 = (_model$scalarsToColor6 = model.scalarsToColors).getUseBelowRangeColor) !== null && _model$scalarsToColor5 !== void 0 && _model$scalarsToColor5.call(_model$scalarsToColor6)) {
631
+ if (model.renderable.getDrawBelowRangeSwatch() && (_scalarsToColors$getU = scalarsToColors.getUseBelowRangeColor) !== null && _scalarsToColors$getU !== void 0 && _scalarsToColors$getU.call(scalarsToColors)) {
568
632
  numberOfExtraColors += 1;
569
633
  }
570
634
 
571
- if (model.drawAboveRangeSwatch && (_model$scalarsToColor7 = (_model$scalarsToColor8 = model.scalarsToColors).getUseAboveRangeColor) !== null && _model$scalarsToColor7 !== void 0 && _model$scalarsToColor7.call(_model$scalarsToColor8)) {
635
+ if (model.renderable.getDrawAboveRangeSwatch() && (_scalarsToColors$getU2 = scalarsToColors.getUseAboveRangeColor) !== null && _scalarsToColors$getU2 !== void 0 && _scalarsToColors$getU2.call(scalarsToColors)) {
572
636
  numberOfExtraColors += 1;
573
637
  }
574
638
 
@@ -577,8 +641,8 @@ function vtkScalarBarActor(publicAPI, model) {
577
641
 
578
642
  var numComps = 1;
579
643
 
580
- if (model.scalarsToColors.getVectorMode() === VectorMode.COMPONENT) {
581
- numComps = model.scalarsToColors.getVectorComponent() + 1;
644
+ if (scalarsToColors.getVectorMode() === VectorMode.COMPONENT) {
645
+ numComps = scalarsToColors.getVectorComponent() + 1;
582
646
  } // create the colored bars
583
647
 
584
648
 
@@ -628,14 +692,66 @@ function vtkScalarBarActor(publicAPI, model) {
628
692
  model.polyData.getPolys().modified();
629
693
  model.polyData.modified();
630
694
  };
695
+ }
631
696
 
632
- publicAPI.getActors = function () {
633
- return [model.barActor, model.tmActor];
697
+ var newScalarBarActorHelper = macro.newInstance(function (publicAPI, model) {
698
+ var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {
699
+ renderable: null
634
700
  };
701
+ Object.assign(model, {}, initialValues); // Inheritance
635
702
 
636
- publicAPI.getNestedProps = function () {
637
- return publicAPI.getActors();
638
- };
703
+ macro.obj(publicAPI, model);
704
+ macro.setGet(publicAPI, model, ['axisTitlePixelOffset', 'tickLabelPixelOffset', 'renderable', 'topTitle']);
705
+ macro.get(publicAPI, model, ['lastSize', 'lastAspectRatio', 'axisTextStyle', 'tickTextStyle', 'barActor', 'tmActor', 'ticks']);
706
+ macro.getArray(publicAPI, model, ['boxPosition', 'boxSize']);
707
+ macro.setArray(publicAPI, model, ['boxPosition', 'boxSize'], 2);
708
+ model.forceUpdate = false;
709
+ model.lastRedrawTime = {};
710
+ macro.obj(model.lastRedrawTime, {
711
+ mtime: 0
712
+ });
713
+ model.lastRebuildTime = {};
714
+ macro.obj(model.lastRebuildTime, {
715
+ mtime: 0
716
+ });
717
+ model.lastSize = [-1, -1];
718
+ model.tmCanvas = document.createElement('canvas');
719
+ model.tmContext = model.tmCanvas.getContext('2d');
720
+ model._tmAtlas = new Map();
721
+ model.barMapper = vtkMapper.newInstance();
722
+ model.barMapper.setInterpolateScalarsBeforeMapping(true);
723
+ model.polyData = vtkPolyData.newInstance();
724
+ model.barMapper.setInputData(model.polyData);
725
+ model.barActor = vtkActor.newInstance();
726
+ model.barActor.setMapper(model.barMapper); // for texture atlas
727
+
728
+ model.tmPolyData = vtkPolyData.newInstance();
729
+ model.tmMapper = vtkMapper.newInstance();
730
+ model.tmMapper.setInputData(model.tmPolyData);
731
+ model.tmTexture = vtkTexture.newInstance();
732
+ model.tmTexture.setInterpolate(false);
733
+ model.tmActor = vtkActor.newInstance({
734
+ parentProp: publicAPI
735
+ });
736
+ model.tmActor.setMapper(model.tmMapper);
737
+ model.tmActor.addTexture(model.tmTexture);
738
+ model.barPosition = [0, 0];
739
+ model.barSize = [0, 0];
740
+ model.boxPosition = [0.88, -0.92];
741
+ model.boxSize = [0.1, 1.1]; // internal variables
742
+
743
+ model.lastTickBounds = [];
744
+ vtkScalarBarActorHelper(publicAPI, model);
745
+ }, 'vtkScalarBarActorHelper'); //
746
+ // Now we define the public class that the application sets view independent
747
+ // properties on. This class is fairly small as it mainly just holds
748
+ // properties setter and getters leaving all calculations to the helper
749
+ // class.
750
+ //
751
+
752
+ function vtkScalarBarActor(publicAPI, model) {
753
+ // Set our className
754
+ model.classHierarchy.push('vtkScalarBarActor');
639
755
 
640
756
  publicAPI.setTickTextStyle = function (tickStyle) {
641
757
  model.tickTextStyle = _objectSpread(_objectSpread({}, model.tickTextStyle), tickStyle);
@@ -647,12 +763,6 @@ function vtkScalarBarActor(publicAPI, model) {
647
763
  publicAPI.modified();
648
764
  };
649
765
 
650
- var setVisibility = macro.chain(publicAPI.setVisibility, model.barActor.setVisibility, model.tmActor.setVisibility);
651
-
652
- publicAPI.setVisibility = function () {
653
- return setVisibility.apply(void 0, arguments).some(Boolean);
654
- };
655
-
656
766
  publicAPI.resetAutoLayoutToDefault = function () {
657
767
  model.autoLayout = defaultAutoLayout(publicAPI, model);
658
768
  };
@@ -700,64 +810,6 @@ function extend(publicAPI, model) {
700
810
  vtkActor.extend(publicAPI, model, initialValues);
701
811
  publicAPI.getProperty().setDiffuse(0.0);
702
812
  publicAPI.getProperty().setAmbient(1.0);
703
- model._tmAtlas = new Map(); // internal variables
704
-
705
- model.lastSize = [800, 800];
706
- model.lastAspectRatio = 1.0;
707
- model.textValues = [];
708
- model.lastTickBounds = [];
709
- model.barMapper = vtkMapper.newInstance();
710
- model.barMapper.setInterpolateScalarsBeforeMapping(true);
711
- model.polyData = vtkPolyData.newInstance();
712
- model.barMapper.setInputData(model.polyData);
713
- model.barActor = vtkActor.newInstance({
714
- parentProp: publicAPI
715
- });
716
- model.barActor.setMapper(model.barMapper);
717
- model.barActor.setProperty(publicAPI.getProperty());
718
- model.lastRedrawTime = {};
719
- macro.obj(model.lastRedrawTime, {
720
- mtime: 0
721
- });
722
- model.lastRebuildTime = {};
723
- macro.obj(model.lastRebuildTime, {
724
- mtime: 0
725
- });
726
- model.textPolyData = vtkPolyData.newInstance(); // for texture atlas
727
-
728
- model.tmPolyData = vtkPolyData.newInstance();
729
- model.tmMapper = vtkMapper.newInstance();
730
- model.tmMapper.setInputData(model.tmPolyData);
731
- model.tmTexture = vtkTexture.newInstance();
732
- model.tmTexture.setInterpolate(false);
733
- model.tmActor = vtkActor.newInstance({
734
- parentProp: publicAPI
735
- });
736
- model.tmActor.setMapper(model.tmMapper);
737
- model.tmActor.addTexture(model.tmTexture);
738
- model.tmActor.setProperty(publicAPI.getProperty());
739
- model.tmCanvas = document.createElement('canvas');
740
- model.tmContext = model.tmCanvas.getContext('2d'); // PixelSpaceCallbackMapper - we do need an empty polydata
741
- // really just used to get the window size which we need to do
742
- // proper text positioning and scaling.
743
-
744
- model.mapper = vtkPixelSpaceCallbackMapper.newInstance();
745
- model.pixelMapperPolyData = vtkPolyData.newInstance();
746
- model.mapper.setInputData(model.pixelMapperPolyData);
747
- model.mapper.setCallback(function (coords, camera, aspect, depthValues, size) {
748
- model.camera = camera;
749
-
750
- if (model.lastSize[0] !== size[0] || model.lastSize[1] !== size[1]) {
751
- model.lastSize[0] = size[0];
752
- model.lastSize[1] = size[1];
753
- model.lastAspectRatio = size[0] / size[1]; // we could use modified, but really the public state is not
754
- // modified
755
-
756
- model.forceUpdate = true;
757
- }
758
-
759
- publicAPI.update();
760
- });
761
813
  macro.setGet(publicAPI, model, ['automated', 'autoLayout', 'axisTitlePixelOffset', 'axisLabel', 'scalarsToColors', 'tickLabelPixelOffset', 'drawNanAnnotation', 'drawBelowRangeSwatch', 'drawAboveRangeSwatch']);
762
814
  macro.get(publicAPI, model, ['axisTextStyle', 'tickTextStyle']);
763
815
  macro.getArray(publicAPI, model, ['boxPosition', 'boxSize']);
@@ -770,7 +822,8 @@ var newInstance = macro.newInstance(extend, 'vtkScalarBarActor'); // -----------
770
822
 
771
823
  var vtkScalarBarActor$1 = {
772
824
  newInstance: newInstance,
773
- extend: extend
825
+ extend: extend,
826
+ newScalarBarActorHelper: newScalarBarActorHelper
774
827
  };
775
828
 
776
829
  export { vtkScalarBarActor$1 as default, extend, newInstance };
@@ -4,6 +4,7 @@ import '../Actor.js';
4
4
  import '../Actor2D.js';
5
5
  import '../PolyDataMapper.js';
6
6
  import '../PolyDataMapper2D.js';
7
+ import '../ScalarBarActor.js';
7
8
  import '../Skybox.js';
8
9
  import '../Texture.js';
9
10
  import '../Glyph3DMapper.js';
@@ -4,6 +4,7 @@ import '../Actor.js';
4
4
  import '../Actor2D.js';
5
5
  import '../PolyDataMapper.js';
6
6
  import '../PolyDataMapper2D.js';
7
+ import '../ScalarBarActor.js';
7
8
  import '../Skybox.js';
8
9
  import '../Texture.js';
9
10
  import '../PixelSpaceCallbackMapper.js';
@@ -0,0 +1,61 @@
1
+ import { newInstance as newInstance$1 } from '../../macros.js';
2
+ import vtkScalarBarActor from '../Core/ScalarBarActor.js';
3
+ import vtkViewNode from '../SceneGraph/ViewNode.js';
4
+ import { registerOverride } from './ViewNodeFactory.js';
5
+
6
+ // vtkOpenGLScalarBarActor methods
7
+ // ----------------------------------------------------------------------------
8
+
9
+ function vtkOpenGLScalarBarActor(publicAPI, model) {
10
+ model.classHierarchy.push('vtkOpenGLScalarBarActor'); // Builds myself.
11
+
12
+ publicAPI.buildPass = function (prepass) {
13
+ if (prepass) {
14
+ model.openGLRenderer = publicAPI.getFirstAncestorOfType('vtkOpenGLRenderer');
15
+ model.openGLRenderWindow = model.openGLRenderer.getParent();
16
+
17
+ if (!model.scalarBarActorHelper.getRenderable()) {
18
+ model.scalarBarActorHelper.setRenderable(model.renderable);
19
+ }
20
+
21
+ publicAPI.prepareNodes();
22
+ publicAPI.addMissingNode(model.scalarBarActorHelper.getBarActor());
23
+ publicAPI.addMissingNode(model.scalarBarActorHelper.getTmActor());
24
+ publicAPI.removeUnusedNodes();
25
+ }
26
+ };
27
+
28
+ publicAPI.opaquePass = function (prepass, renderPass) {
29
+ if (prepass) {
30
+ var camera = model.openGLRenderer ? model.openGLRenderer.getRenderable().getActiveCamera() : null;
31
+ var tsize = model.openGLRenderer.getTiledSizeAndOrigin();
32
+ model.scalarBarActorHelper.updateAPISpecificData([tsize.usize, tsize.vsize], camera, model.openGLRenderWindow.getRenderable());
33
+ }
34
+ };
35
+ } // ----------------------------------------------------------------------------
36
+ // Object factory
37
+ // ----------------------------------------------------------------------------
38
+
39
+
40
+ var DEFAULT_VALUES = {}; // ----------------------------------------------------------------------------
41
+
42
+ function extend(publicAPI, model) {
43
+ var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
44
+ Object.assign(model, DEFAULT_VALUES, initialValues); // Inheritance
45
+
46
+ vtkViewNode.extend(publicAPI, model, initialValues);
47
+ model.scalarBarActorHelper = vtkScalarBarActor.newScalarBarActorHelper(); // Object methods
48
+
49
+ vtkOpenGLScalarBarActor(publicAPI, model);
50
+ } // ----------------------------------------------------------------------------
51
+
52
+ var newInstance = newInstance$1(extend, 'vtkOpenGLScalarBarActor'); // ----------------------------------------------------------------------------
53
+
54
+ var index = {
55
+ newInstance: newInstance,
56
+ extend: extend
57
+ }; // Register ourself to OpenGL backend if imported
58
+
59
+ registerOverride('vtkScalarBarActor', newInstance);
60
+
61
+ export { index as default, extend, newInstance };
@@ -4,6 +4,7 @@ import '../OpenGL/Actor.js';
4
4
  import '../OpenGL/Actor2D.js';
5
5
  import '../OpenGL/PolyDataMapper.js';
6
6
  import '../OpenGL/PolyDataMapper2D.js';
7
+ import '../OpenGL/ScalarBarActor.js';
7
8
  import '../OpenGL/Skybox.js';
8
9
  import '../OpenGL/Texture.js';
9
10
  import '../OpenGL/Glyph3DMapper.js';
@@ -19,6 +20,7 @@ import '../WebGPU/Camera.js';
19
20
  import '../WebGPU/Renderer.js';
20
21
  import '../WebGPU/Actor.js';
21
22
  import '../WebGPU/PolyDataMapper.js';
23
+ import '../WebGPU/ScalarBarActor.js';
22
24
  import '../WebGPU/Texture.js';
23
25
  import '../WebGPU/Glyph3DMapper.js';
24
26
  import '../WebGPU/ImageMapper.js';
@@ -4,6 +4,7 @@ import '../OpenGL/Actor.js';
4
4
  import '../OpenGL/Actor2D.js';
5
5
  import '../OpenGL/PolyDataMapper.js';
6
6
  import '../OpenGL/PolyDataMapper2D.js';
7
+ import '../OpenGL/ScalarBarActor.js';
7
8
  import '../OpenGL/Skybox.js';
8
9
  import '../OpenGL/Texture.js';
9
10
  import '../OpenGL/PixelSpaceCallbackMapper.js';
@@ -11,5 +12,6 @@ import '../WebGPU/Camera.js';
11
12
  import '../WebGPU/Renderer.js';
12
13
  import '../WebGPU/Actor.js';
13
14
  import '../WebGPU/PolyDataMapper.js';
15
+ import '../WebGPU/ScalarBarActor.js';
14
16
  import '../WebGPU/Texture.js';
15
17
  import '../WebGPU/PixelSpaceCallbackMapper.js';
@@ -84,8 +84,8 @@ function vtkWebGPUHardwareSelectionPass(publicAPI, model) {
84
84
  fDesc.setCode(code);
85
85
  });
86
86
  var renDesc = model.selectionRenderEncoder.getDescription();
87
- renDesc.colorAttachments[0].loadValue = [0.0, 0.0, 0.0, 0.0];
88
- renDesc.depthStencilAttachment.stencilLoadValue = 'load';
87
+ renDesc.colorAttachments[0].clearValue = [0.0, 0.0, 0.0, 0.0];
88
+ renDesc.depthStencilAttachment.stencilLoadOp = 'load';
89
89
  model.selectionRenderEncoder.setPipelineSettings({
90
90
  primitive: {
91
91
  cullMode: 'none'
@@ -96,18 +96,20 @@ function vtkWebGPUOrderIndependentTranslucentPass(publicAPI, model) {
96
96
  var rDesc = model.translucentRenderEncoder.getDescription();
97
97
  rDesc.colorAttachments = [{
98
98
  view: undefined,
99
- loadValue: [0.0, 0.0, 0.0, 0.0],
99
+ clearValue: [0.0, 0.0, 0.0, 0.0],
100
+ loadOp: 'clear',
100
101
  storeOp: 'store'
101
102
  }, {
102
103
  view: undefined,
103
- loadValue: [1.0, 0.0, 0.0, 0.0],
104
+ clearValue: [1.0, 0.0, 0.0, 0.0],
105
+ loadOp: 'clear',
104
106
  storeOp: 'store'
105
107
  }];
106
108
  rDesc.depthStencilAttachment = {
107
109
  view: undefined,
108
- depthLoadValue: 'load',
110
+ depthLoadOp: 'load',
109
111
  depthStoreOp: 'store',
110
- stencilLoadValue: 'load',
112
+ stencilLoadOp: 'load',
111
113
  stencilStoreOp: 'store'
112
114
  };
113
115
  model.translucentRenderEncoder.setReplaceShaderCodeFunction(function (pipeline) {
@@ -167,7 +169,7 @@ function vtkWebGPUOrderIndependentTranslucentPass(publicAPI, model) {
167
169
  model.translucentFinalEncoder.setDescription({
168
170
  colorAttachments: [{
169
171
  view: null,
170
- loadValue: 'load',
172
+ loadOp: 'load',
171
173
  storeOp: 'store'
172
174
  }]
173
175
  });
@@ -2,6 +2,7 @@ import '../Camera.js';
2
2
  import '../Renderer.js';
3
3
  import '../Actor.js';
4
4
  import '../PolyDataMapper.js';
5
+ import '../ScalarBarActor.js';
5
6
  import '../Texture.js';
6
7
  import '../Glyph3DMapper.js';
7
8
  import '../ImageMapper.js';
@@ -2,5 +2,6 @@ import '../Camera.js';
2
2
  import '../Renderer.js';
3
3
  import '../Actor.js';
4
4
  import '../PolyDataMapper.js';
5
+ import '../ScalarBarActor.js';
5
6
  import '../Texture.js';
6
7
  import '../PixelSpaceCallbackMapper.js';
@@ -138,14 +138,16 @@ function extend(publicAPI, model) {
138
138
  model.description = {
139
139
  colorAttachments: [{
140
140
  view: undefined,
141
- loadValue: 'load',
141
+ loadOp: 'load',
142
142
  storeOp: 'store'
143
143
  }],
144
144
  depthStencilAttachment: {
145
145
  view: undefined,
146
- depthLoadValue: 0.0,
146
+ depthLoadOp: 'clear',
147
+ depthClearValue: 0.0,
147
148
  depthStoreOp: 'store',
148
- stencilLoadValue: 0,
149
+ stencilLoadOp: 'clear',
150
+ stencilClearValue: 0,
149
151
  stencilStoreOp: 'store'
150
152
  }
151
153
  }; // default shader code just writes out the computedColor
@@ -0,0 +1,61 @@
1
+ import { newInstance as newInstance$1 } from '../../macros.js';
2
+ import vtkScalarBarActor from '../Core/ScalarBarActor.js';
3
+ import vtkViewNode from '../SceneGraph/ViewNode.js';
4
+ import { registerOverride } from './ViewNodeFactory.js';
5
+
6
+ // vtkWebGPUScalarBarActor methods
7
+ // ----------------------------------------------------------------------------
8
+
9
+ function vtkWebGPUScalarBarActor(publicAPI, model) {
10
+ model.classHierarchy.push('vtkWebGPUScalarBarActor'); // Builds myself.
11
+
12
+ publicAPI.buildPass = function (prepass) {
13
+ if (prepass) {
14
+ model.WebGPURenderer = publicAPI.getFirstAncestorOfType('vtkWebGPURenderer');
15
+ model.WebGPURenderWindow = model.WebGPURenderer.getParent();
16
+
17
+ if (!model.scalarBarActorHelper.getRenderable()) {
18
+ model.scalarBarActorHelper.setRenderable(model.renderable);
19
+ }
20
+
21
+ publicAPI.prepareNodes();
22
+ publicAPI.addMissingNode(model.scalarBarActorHelper.getBarActor());
23
+ publicAPI.addMissingNode(model.scalarBarActorHelper.getTmActor());
24
+ publicAPI.removeUnusedNodes();
25
+ }
26
+ };
27
+
28
+ publicAPI.opaquePass = function (prepass, renderPass) {
29
+ if (prepass) {
30
+ var camera = model.WebGPURenderer ? model.WebGPURenderer.getRenderable().getActiveCamera() : null;
31
+ var tsize = model.WebGPURenderer.getTiledSizeAndOrigin();
32
+ model.scalarBarActorHelper.updateAPISpecificData([tsize.usize, tsize.vsize], camera, model.WebGPURenderWindow.getRenderable());
33
+ }
34
+ };
35
+ } // ----------------------------------------------------------------------------
36
+ // Object factory
37
+ // ----------------------------------------------------------------------------
38
+
39
+
40
+ var DEFAULT_VALUES = {}; // ----------------------------------------------------------------------------
41
+
42
+ function extend(publicAPI, model) {
43
+ var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
44
+ Object.assign(model, DEFAULT_VALUES, initialValues); // Inheritance
45
+
46
+ vtkViewNode.extend(publicAPI, model, initialValues);
47
+ model.scalarBarActorHelper = vtkScalarBarActor.newScalarBarActorHelper(); // Object methods
48
+
49
+ vtkWebGPUScalarBarActor(publicAPI, model);
50
+ } // ----------------------------------------------------------------------------
51
+
52
+ var newInstance = newInstance$1(extend, 'vtkWebGPUScalarBarActor'); // ----------------------------------------------------------------------------
53
+
54
+ var index = {
55
+ newInstance: newInstance,
56
+ extend: extend
57
+ }; // Register ourself to WebGPU backend if imported
58
+
59
+ registerOverride('vtkScalarBarActor', newInstance);
60
+
61
+ export { index as default, extend, newInstance };
@@ -206,14 +206,20 @@ function vtkWebGPUVolumePass(publicAPI, model) {
206
206
  if (!model._animationRateSubscription) {
207
207
  // when the animation frame rate changes recompute the scale factor
208
208
  model._animationRateSubscription = rwi.onAnimationFrameRateUpdate(function () {
209
- var frate = rwi.getRecentAnimationFrameRate();
210
- var targetScale = model._lastScale * rwi.getDesiredUpdateRate() / frate;
211
- model._lastScale = targetScale; // clamp scale to some reasonable values.
212
- // Below 1.5 we will just be using full resolution as that is close enough
213
- // Above 400 seems like a lot so we limit to that 1/20th per axis
214
-
215
- if (model._lastScale > 400) {
216
- model._lastScale = 400;
209
+ var firstMapper = model.volumes[0].getRenderable().getMapper();
210
+
211
+ if (firstMapper.getAutoAdjustSampleDistances()) {
212
+ var frate = rwi.getRecentAnimationFrameRate();
213
+ var targetScale = model._lastScale * rwi.getDesiredUpdateRate() / frate;
214
+ model._lastScale = targetScale; // clamp scale to some reasonable values.
215
+ // Below 1.5 we will just be using full resolution as that is close enough
216
+ // Above 400 seems like a lot so we limit to that 1/20th per axis
217
+
218
+ if (model._lastScale > 400) {
219
+ model._lastScale = 400;
220
+ }
221
+ } else {
222
+ model._lastScale = firstMapper.getImageSampleDistance() * firstMapper.getImageSampleDistance();
217
223
  }
218
224
 
219
225
  if (model._lastScale < 1.5) {
@@ -384,11 +390,13 @@ function vtkWebGPUVolumePass(publicAPI, model) {
384
390
  model._depthRangeEncoder.setDescription({
385
391
  colorAttachments: [{
386
392
  view: null,
387
- loadValue: [0.0, 0.0, 0.0, 0.0],
393
+ clearValue: [0.0, 0.0, 0.0, 0.0],
394
+ loadOp: 'clear',
388
395
  storeOp: 'store'
389
396
  }, {
390
397
  view: null,
391
- loadValue: [1.0, 1.0, 1.0, 1.0],
398
+ clearValue: [1.0, 1.0, 1.0, 1.0],
399
+ loadOp: 'clear',
392
400
  storeOp: 'store'
393
401
  }]
394
402
  });
@@ -498,7 +506,8 @@ function vtkWebGPUVolumePass(publicAPI, model) {
498
506
  model._clearEncoder.setDescription({
499
507
  colorAttachments: [{
500
508
  view: null,
501
- loadValue: [0.0, 0.0, 0.0, 0.0],
509
+ clearValue: [0.0, 0.0, 0.0, 0.0],
510
+ loadOp: 'clear',
502
511
  storeOp: 'store'
503
512
  }]
504
513
  });
@@ -535,7 +544,7 @@ function vtkWebGPUVolumePass(publicAPI, model) {
535
544
  model._copyEncoder.setDescription({
536
545
  colorAttachments: [{
537
546
  view: null,
538
- loadValue: 'load',
547
+ loadOp: 'load',
539
548
  storeOp: 'store'
540
549
  }]
541
550
  });
@@ -574,7 +583,7 @@ function vtkWebGPUVolumePass(publicAPI, model) {
574
583
  model._mergeEncoder.setDescription({
575
584
  colorAttachments: [{
576
585
  view: null,
577
- loadValue: 'load',
586
+ loadOp: 'load',
578
587
  storeOp: 'store'
579
588
  }]
580
589
  });
@@ -9,7 +9,7 @@ import vtkWebGPUSampler from './Sampler.js';
9
9
  import vtkWebGPUTypes from './Types.js';
10
10
  import { BlendMode } from '../Core/VolumeMapper/Constants.js';
11
11
 
12
- var volFragTemplate = "\n//VTK::Renderer::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::TCoord::Dec\n\n//VTK::Volume::TraverseDec\n\n//VTK::RenderEncoder::Dec\n\n//VTK::IOStructs::Dec\n\nfn getTextureValue(vTex: texture_3d<f32>, tpos: vec4<f32>) -> f32\n{\n // todo multicomponent support\n return textureSampleLevel(vTex, clampSampler, tpos.xyz, 0.0).r;\n}\n\nfn getGradient(vTex: texture_3d<f32>, tpos: vec4<f32>, vNum: i32, scalar: f32) -> vec4<f32>\n{\n var result: vec4<f32>;\n\n var tstep: vec4<f32> = volumeSSBO.values[vNum].tstep;\n result.x = getTextureValue(vTex, tpos + vec4<f32>(tstep.x, 0.0, 0.0, 1.0)) - scalar;\n result.y = getTextureValue(vTex, tpos + vec4<f32>(0.0, tstep.y, 0.0, 1.0)) - scalar;\n result.z = getTextureValue(vTex, tpos + vec4<f32>(0.0, 0.0, tstep.z, 1.0)) - scalar;\n\n // divide by spacing\n result = result / volumeSSBO.values[vNum].spacing;\n\n var grad: f32 = length(result.xyz);\n\n // // rotate to View Coords, needed for lighting and shading\n // result.xyz =\n // result.x * vPlaneNormal0 +\n // result.y * vPlaneNormal2 +\n // result.z * vPlaneNormal4;\n\n if (grad > 0.0)\n {\n result = result * (1.0 / grad);\n }\n\n result.w = grad;\n\n return result;\n}\n\nfn processVolume(vTex: texture_3d<f32>, vNum: i32, cNum: i32, posSC: vec4<f32>, tfunRows: f32) -> vec4<f32>\n{\n var outColor: vec4<f32> = vec4<f32>(0.0, 0.0, 0.0, 0.0);\n\n // convert to tcoords and reject if outside the volume\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*posSC;\n if (tpos.x < 0.0 || tpos.y < 0.0 || tpos.z < 0.0 ||\n tpos.x > 1.0 || tpos.y > 1.0 || tpos.z > 1.0) { return outColor; }\n\n var scalar: f32 = getTextureValue(vTex, tpos);\n\n var coord: vec2<f32> =\n vec2<f32>(scalar * componentSSBO.values[cNum].cScale + componentSSBO.values[cNum].cShift,\n (0.5 + 2.0 * f32(vNum)) / tfunRows);\n var color: vec4<f32> = textureSampleLevel(tfunTexture, clampSampler, coord, 0.0);\n\n var gofactor: f32 = 1.0;\n if (componentSSBO.values[cNum].gomin < 1.0)\n {\n var normal: vec4<f32> = getGradient(vTex, tpos, vNum, scalar);\n gofactor = clamp(normal.a*componentSSBO.values[cNum].goScale + componentSSBO.values[cNum].goShift,\n componentSSBO.values[cNum].gomin, componentSSBO.values[cNum].gomax);\n }\n\n coord.x = (scalar * componentSSBO.values[cNum].oScale + componentSSBO.values[cNum].oShift);\n var opacity: f32 = textureSampleLevel(ofunTexture, clampSampler, coord, 0.0).r;\n\n outColor = vec4<f32>(color.rgb, gofactor * opacity);\n\n//VTK::Volume::Process\n\n return outColor;\n}\n\n// adjust the start and end point of a raycast such that it intersects the unit cube.\n// This function is used to take a raycast starting point and step vector\n// and numSteps and return the startijng and ending steps for intersecting the\n// unit cube. Recall for a 3D texture, the unit cube is the range of texture coordsinates\n// that have valid values. So this funtion can be used to take a ray in texture coordinates\n// and bound it to intersecting the texture.\n//\nfn adjustBounds(tpos: vec4<f32>, tstep: vec4<f32>, numSteps: f32) -> vec2<f32>\n{\n var result: vec2<f32> = vec2<f32>(0.0, numSteps);\n var tpos2: vec4<f32> = tpos + tstep*numSteps;\n\n // move tpos to the start of the volume\n var adjust: f32 =\n min(\n max(tpos.x/tstep.x, (tpos.x - 1.0)/tstep.x),\n min(\n max((tpos.y - 1.0)/tstep.y, tpos.y/tstep.y),\n max((tpos.z - 1.0)/tstep.z, tpos.z/tstep.z)));\n if (adjust < 0.0)\n {\n result.x = result.x - adjust;\n }\n\n // adjust length to the end\n adjust =\n max(\n min(tpos2.x/tstep.x, (tpos2.x - 1.0)/tstep.x),\n max(\n min((tpos2.y - 1.0)/tstep.y, tpos2.y/tstep.y),\n min((tpos2.z - 1.0)/tstep.z, tpos2.z/tstep.z)));\n if (adjust > 0.0)\n {\n result.y = result.y - adjust;\n }\n\n return result;\n}\n\nfn getSimpleColor(scalar: f32, vNum: i32, cNum: i32) -> vec4<f32>\n{\n // how many rows (tfuns) do we have in our tfunTexture\n var tfunRows: f32 = f32(textureDimensions(tfunTexture).y);\n\n var coord: vec2<f32> =\n vec2<f32>(scalar * componentSSBO.values[cNum].cScale + componentSSBO.values[cNum].cShift,\n (0.5 + 2.0 * f32(vNum)) / tfunRows);\n var color: vec4<f32> = textureSampleLevel(tfunTexture, clampSampler, coord, 0.0);\n coord.x = (scalar * componentSSBO.values[cNum].oScale + componentSSBO.values[cNum].oShift);\n var opacity: f32 = textureSampleLevel(ofunTexture, clampSampler, coord, 0.0).r;\n return vec4<f32>(color.rgb, opacity);\n}\n\nfn traverseMax(vTex: texture_3d<f32>, vNum: i32, cNum: i32, rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>)\n{\n // convert to tcoords and reject if outside the volume\n var numSteps: f32 = rayLengthSC/mapperUBO.SampleDistance;\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*minPosSC;\n var tpos2: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*(minPosSC + rayStepSC);\n var tstep: vec4<f32> = tpos2 - tpos;\n\n var rayBounds: vec2<f32> = adjustBounds(tpos, tstep, numSteps);\n\n // did we hit anything\n if (rayBounds.x >= rayBounds.y)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n return;\n }\n\n tpos = tpos + tstep*rayBounds.x;\n var curDist: f32 = rayBounds.x;\n var maxVal: f32 = -1.0e37;\n loop\n {\n var scalar: f32 = getTextureValue(vTex, tpos);\n if (scalar > maxVal)\n {\n maxVal = scalar;\n }\n\n // increment position\n curDist = curDist + 1.0;\n tpos = tpos + tstep;\n\n // check if we have reached a terminating condition\n if (curDist > rayBounds.y) { break; }\n }\n\n // process to get the color and opacity\n traverseVals[vNum] = getSimpleColor(maxVal, vNum, cNum);\n}\n\nfn traverseMin(vTex: texture_3d<f32>, vNum: i32, cNum: i32, rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>)\n{\n // convert to tcoords and reject if outside the volume\n var numSteps: f32 = rayLengthSC/mapperUBO.SampleDistance;\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*minPosSC;\n var tpos2: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*(minPosSC + rayStepSC);\n var tstep: vec4<f32> = tpos2 - tpos;\n\n var rayBounds: vec2<f32> = adjustBounds(tpos, tstep, numSteps);\n\n // did we hit anything\n if (rayBounds.x >= rayBounds.y)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n return;\n }\n\n tpos = tpos + tstep*rayBounds.x;\n var curDist: f32 = rayBounds.x;\n var minVal: f32 = 1.0e37;\n loop\n {\n var scalar: f32 = getTextureValue(vTex, tpos);\n if (scalar < minVal)\n {\n minVal = scalar;\n }\n\n // increment position\n curDist = curDist + 1.0;\n tpos = tpos + tstep;\n\n // check if we have reached a terminating condition\n if (curDist > rayBounds.y) { break; }\n }\n\n // process to get the color and opacity\n traverseVals[vNum] = getSimpleColor(minVal, vNum, cNum);\n}\n\nfn traverseAverage(vTex: texture_3d<f32>, vNum: i32, cNum: i32, rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>)\n{\n // convert to tcoords and reject if outside the volume\n var numSteps: f32 = rayLengthSC/mapperUBO.SampleDistance;\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*minPosSC;\n var tpos2: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*(minPosSC + rayStepSC);\n var tstep: vec4<f32> = tpos2 - tpos;\n\n var rayBounds: vec2<f32> = adjustBounds(tpos, tstep, numSteps);\n\n // did we hit anything\n if (rayBounds.x >= rayBounds.y)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n return;\n }\n\n let ipRange: vec4<f32> = volumeSSBO.values[vNum].ipScalarRange;\n tpos = tpos + tstep*rayBounds.x;\n var curDist: f32 = rayBounds.x;\n var avgVal: f32 = 0.0;\n var sampleCount: f32 = 0.0;\n loop\n {\n var sample: f32 = getTextureValue(vTex, tpos);\n // right now leave filtering off until WebGL changes get merged\n // if (ipRange.z == 0.0 || sample >= ipRange.x && sample <= ipRange.y)\n // {\n avgVal = avgVal + sample;\n sampleCount = sampleCount + 1.0;\n // }\n\n // increment position\n curDist = curDist + 1.0;\n tpos = tpos + tstep;\n\n // check if we have reached a terminating condition\n if (curDist > rayBounds.y) { break; }\n }\n\n if (sampleCount <= 0.0)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n }\n\n // process to get the color and opacity\n traverseVals[vNum] = getSimpleColor(avgVal/sampleCount, vNum, cNum);\n}\n\nfn traverseAdditive(vTex: texture_3d<f32>, vNum: i32, cNum: i32, rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>)\n{\n // convert to tcoords and reject if outside the volume\n var numSteps: f32 = rayLengthSC/mapperUBO.SampleDistance;\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*minPosSC;\n var tpos2: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*(minPosSC + rayStepSC);\n var tstep: vec4<f32> = tpos2 - tpos;\n\n var rayBounds: vec2<f32> = adjustBounds(tpos, tstep, numSteps);\n\n // did we hit anything\n if (rayBounds.x >= rayBounds.y)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n return;\n }\n\n let ipRange: vec4<f32> = volumeSSBO.values[vNum].ipScalarRange;\n tpos = tpos + tstep*rayBounds.x;\n var curDist: f32 = rayBounds.x;\n var sumVal: f32 = 0.0;\n loop\n {\n var sample: f32 = getTextureValue(vTex, tpos);\n // right now leave filtering off until WebGL changes get merged\n // if (ipRange.z == 0.0 || sample >= ipRange.x && sample <= ipRange.y)\n // {\n sumVal = sumVal + sample;\n // }\n\n // increment position\n curDist = curDist + 1.0;\n tpos = tpos + tstep;\n\n // check if we have reached a terminating condition\n if (curDist > rayBounds.y) { break; }\n }\n\n // process to get the color and opacity\n traverseVals[vNum] = getSimpleColor(sumVal, vNum, cNum);\n}\n\nfn composite(rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>) -> vec4<f32>\n{\n // initial ray position is at the beginning\n var rayPosSC: vec4<f32> = minPosSC;\n\n // how many rows (tfuns) do we have in our tfunTexture\n var tfunRows: f32 = f32(textureDimensions(tfunTexture).y);\n\n var curDist: f32 = 0.0;\n var computedColor: vec4<f32> = vec4<f32>(0.0, 0.0, 0.0, 0.0);\n var sampleColor: vec4<f32>;\n//VTK::Volume::TraverseCalls\n\n loop\n {\n // for each volume, sample and accumulate color\n//VTK::Volume::CompositeCalls\n\n // increment position\n curDist = curDist + mapperUBO.SampleDistance;\n rayPosSC = rayPosSC + rayStepSC;\n\n // check if we have reached a terminating condition\n if (curDist > rayLengthSC) { break; }\n if (computedColor.a > 0.98) { break; }\n }\n return computedColor;\n}\n\n@stage(fragment)\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output: fragmentOutput;\n\n var rayMax: f32 = textureSampleLevel(maxTexture, clampSampler, input.tcoordVS, 0.0).r;\n var rayMin: f32 = textureSampleLevel(minTexture, clampSampler, input.tcoordVS, 0.0).r;\n\n // discard empty rays\n if (rayMax <= rayMin) { discard; }\n else\n {\n // compute start and end ray positions in view coordinates\n var minPosSC: vec4<f32> = rendererUBO.PCSCMatrix*vec4<f32>(2.0 * input.tcoordVS.x - 1.0, 1.0 - 2.0 * input.tcoordVS.y, rayMax, 1.0);\n minPosSC = minPosSC * (1.0 / minPosSC.w);\n var maxPosSC: vec4<f32> = rendererUBO.PCSCMatrix*vec4<f32>(2.0 * input.tcoordVS.x - 1.0, 1.0 - 2.0 * input.tcoordVS.y, rayMin, 1.0);\n maxPosSC = maxPosSC * (1.0 / maxPosSC.w);\n\n var rayLengthSC: f32 = distance(minPosSC.xyz, maxPosSC.xyz);\n var rayStepSC: vec4<f32> = (maxPosSC - minPosSC)*(mapperUBO.SampleDistance/rayLengthSC);\n rayStepSC.w = 0.0;\n\n var computedColor: vec4<f32>;\n\n//VTK::Volume::Loop\n\n//VTK::RenderEncoder::Impl\n }\n\n return output;\n}\n";
12
+ var volFragTemplate = "\n//VTK::Renderer::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::TCoord::Dec\n\n//VTK::Volume::TraverseDec\n\n//VTK::RenderEncoder::Dec\n\n//VTK::IOStructs::Dec\n\nfn getTextureValue(vTex: texture_3d<f32>, tpos: vec4<f32>) -> f32\n{\n // todo multicomponent support\n return textureSampleLevel(vTex, clampSampler, tpos.xyz, 0.0).r;\n}\n\nfn getGradient(vTex: texture_3d<f32>, tpos: vec4<f32>, vNum: i32, scalar: f32) -> vec4<f32>\n{\n var result: vec4<f32>;\n\n var tstep: vec4<f32> = volumeSSBO.values[vNum].tstep;\n result.x = getTextureValue(vTex, tpos + vec4<f32>(tstep.x, 0.0, 0.0, 1.0)) - scalar;\n result.y = getTextureValue(vTex, tpos + vec4<f32>(0.0, tstep.y, 0.0, 1.0)) - scalar;\n result.z = getTextureValue(vTex, tpos + vec4<f32>(0.0, 0.0, tstep.z, 1.0)) - scalar;\n result.w = 0.0;\n\n // divide by spacing as that is our delta\n result = result / volumeSSBO.values[vNum].spacing;\n // now we have a gradient in unit tcoords\n\n var grad: f32 = length(result.xyz);\n if (grad > 0.0)\n {\n // rotate to View Coords, needed for lighting and shading\n var nMat: mat4x4<f32> = rendererUBO.SCVCMatrix * volumeSSBO.values[vNum].planeNormals;\n result = nMat * result;\n result = result / length(result);\n }\n\n // store gradient magnitude in .w\n result.w = grad;\n\n return result;\n}\n\nfn processVolume(vTex: texture_3d<f32>, vNum: i32, cNum: i32, posSC: vec4<f32>, tfunRows: f32) -> vec4<f32>\n{\n var outColor: vec4<f32> = vec4<f32>(0.0, 0.0, 0.0, 0.0);\n\n // convert to tcoords and reject if outside the volume\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*posSC;\n if (tpos.x < 0.0 || tpos.y < 0.0 || tpos.z < 0.0 ||\n tpos.x > 1.0 || tpos.y > 1.0 || tpos.z > 1.0) { return outColor; }\n\n var scalar: f32 = getTextureValue(vTex, tpos);\n\n var coord: vec2<f32> =\n vec2<f32>(scalar * componentSSBO.values[cNum].cScale + componentSSBO.values[cNum].cShift,\n (0.5 + 2.0 * f32(vNum)) / tfunRows);\n var color: vec4<f32> = textureSampleLevel(tfunTexture, clampSampler, coord, 0.0);\n\n var gofactor: f32 = 1.0;\n var normal: vec4<f32> = vec4<f32>(0.0,0.0,0.0,0.0);\n if (componentSSBO.values[cNum].gomin < 1.0 || volumeSSBO.values[vNum].shade[0] > 0.0)\n {\n normal = getGradient(vTex, tpos, vNum, scalar);\n if (componentSSBO.values[cNum].gomin < 1.0)\n {\n gofactor = clamp(normal.a*componentSSBO.values[cNum].goScale + componentSSBO.values[cNum].goShift,\n componentSSBO.values[cNum].gomin, componentSSBO.values[cNum].gomax);\n }\n }\n\n coord.x = (scalar * componentSSBO.values[cNum].oScale + componentSSBO.values[cNum].oShift);\n var opacity: f32 = textureSampleLevel(ofunTexture, clampSampler, coord, 0.0).r;\n\n if (volumeSSBO.values[vNum].shade[0] > 0.0)\n {\n color = color*abs(normal.z);\n }\n\n outColor = vec4<f32>(color.rgb, gofactor * opacity);\n\n return outColor;\n}\n\n// adjust the start and end point of a raycast such that it intersects the unit cube.\n// This function is used to take a raycast starting point and step vector\n// and numSteps and return the startijng and ending steps for intersecting the\n// unit cube. Recall for a 3D texture, the unit cube is the range of texture coordsinates\n// that have valid values. So this funtion can be used to take a ray in texture coordinates\n// and bound it to intersecting the texture.\n//\nfn adjustBounds(tpos: vec4<f32>, tstep: vec4<f32>, numSteps: f32) -> vec2<f32>\n{\n var result: vec2<f32> = vec2<f32>(0.0, numSteps);\n var tpos2: vec4<f32> = tpos + tstep*numSteps;\n\n // move tpos to the start of the volume\n var adjust: f32 =\n min(\n max(tpos.x/tstep.x, (tpos.x - 1.0)/tstep.x),\n min(\n max((tpos.y - 1.0)/tstep.y, tpos.y/tstep.y),\n max((tpos.z - 1.0)/tstep.z, tpos.z/tstep.z)));\n if (adjust < 0.0)\n {\n result.x = result.x - adjust;\n }\n\n // adjust length to the end\n adjust =\n max(\n min(tpos2.x/tstep.x, (tpos2.x - 1.0)/tstep.x),\n max(\n min((tpos2.y - 1.0)/tstep.y, tpos2.y/tstep.y),\n min((tpos2.z - 1.0)/tstep.z, tpos2.z/tstep.z)));\n if (adjust > 0.0)\n {\n result.y = result.y - adjust;\n }\n\n return result;\n}\n\nfn getSimpleColor(scalar: f32, vNum: i32, cNum: i32) -> vec4<f32>\n{\n // how many rows (tfuns) do we have in our tfunTexture\n var tfunRows: f32 = f32(textureDimensions(tfunTexture).y);\n\n var coord: vec2<f32> =\n vec2<f32>(scalar * componentSSBO.values[cNum].cScale + componentSSBO.values[cNum].cShift,\n (0.5 + 2.0 * f32(vNum)) / tfunRows);\n var color: vec4<f32> = textureSampleLevel(tfunTexture, clampSampler, coord, 0.0);\n coord.x = (scalar * componentSSBO.values[cNum].oScale + componentSSBO.values[cNum].oShift);\n var opacity: f32 = textureSampleLevel(ofunTexture, clampSampler, coord, 0.0).r;\n return vec4<f32>(color.rgb, opacity);\n}\n\nfn traverseMax(vTex: texture_3d<f32>, vNum: i32, cNum: i32, rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>)\n{\n // convert to tcoords and reject if outside the volume\n var numSteps: f32 = rayLengthSC/mapperUBO.SampleDistance;\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*minPosSC;\n var tpos2: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*(minPosSC + rayStepSC);\n var tstep: vec4<f32> = tpos2 - tpos;\n\n var rayBounds: vec2<f32> = adjustBounds(tpos, tstep, numSteps);\n\n // did we hit anything\n if (rayBounds.x >= rayBounds.y)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n return;\n }\n\n tpos = tpos + tstep*rayBounds.x;\n var curDist: f32 = rayBounds.x;\n var maxVal: f32 = -1.0e37;\n loop\n {\n var scalar: f32 = getTextureValue(vTex, tpos);\n if (scalar > maxVal)\n {\n maxVal = scalar;\n }\n\n // increment position\n curDist = curDist + 1.0;\n tpos = tpos + tstep;\n\n // check if we have reached a terminating condition\n if (curDist > rayBounds.y) { break; }\n }\n\n // process to get the color and opacity\n traverseVals[vNum] = getSimpleColor(maxVal, vNum, cNum);\n}\n\nfn traverseMin(vTex: texture_3d<f32>, vNum: i32, cNum: i32, rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>)\n{\n // convert to tcoords and reject if outside the volume\n var numSteps: f32 = rayLengthSC/mapperUBO.SampleDistance;\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*minPosSC;\n var tpos2: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*(minPosSC + rayStepSC);\n var tstep: vec4<f32> = tpos2 - tpos;\n\n var rayBounds: vec2<f32> = adjustBounds(tpos, tstep, numSteps);\n\n // did we hit anything\n if (rayBounds.x >= rayBounds.y)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n return;\n }\n\n tpos = tpos + tstep*rayBounds.x;\n var curDist: f32 = rayBounds.x;\n var minVal: f32 = 1.0e37;\n loop\n {\n var scalar: f32 = getTextureValue(vTex, tpos);\n if (scalar < minVal)\n {\n minVal = scalar;\n }\n\n // increment position\n curDist = curDist + 1.0;\n tpos = tpos + tstep;\n\n // check if we have reached a terminating condition\n if (curDist > rayBounds.y) { break; }\n }\n\n // process to get the color and opacity\n traverseVals[vNum] = getSimpleColor(minVal, vNum, cNum);\n}\n\nfn traverseAverage(vTex: texture_3d<f32>, vNum: i32, cNum: i32, rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>)\n{\n // convert to tcoords and reject if outside the volume\n var numSteps: f32 = rayLengthSC/mapperUBO.SampleDistance;\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*minPosSC;\n var tpos2: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*(minPosSC + rayStepSC);\n var tstep: vec4<f32> = tpos2 - tpos;\n\n var rayBounds: vec2<f32> = adjustBounds(tpos, tstep, numSteps);\n\n // did we hit anything\n if (rayBounds.x >= rayBounds.y)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n return;\n }\n\n let ipRange: vec4<f32> = volumeSSBO.values[vNum].ipScalarRange;\n tpos = tpos + tstep*rayBounds.x;\n var curDist: f32 = rayBounds.x;\n var avgVal: f32 = 0.0;\n var sampleCount: f32 = 0.0;\n loop\n {\n var sample: f32 = getTextureValue(vTex, tpos);\n // right now leave filtering off until WebGL changes get merged\n // if (ipRange.z == 0.0 || sample >= ipRange.x && sample <= ipRange.y)\n // {\n avgVal = avgVal + sample;\n sampleCount = sampleCount + 1.0;\n // }\n\n // increment position\n curDist = curDist + 1.0;\n tpos = tpos + tstep;\n\n // check if we have reached a terminating condition\n if (curDist > rayBounds.y) { break; }\n }\n\n if (sampleCount <= 0.0)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n }\n\n // process to get the color and opacity\n traverseVals[vNum] = getSimpleColor(avgVal/sampleCount, vNum, cNum);\n}\n\nfn traverseAdditive(vTex: texture_3d<f32>, vNum: i32, cNum: i32, rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>)\n{\n // convert to tcoords and reject if outside the volume\n var numSteps: f32 = rayLengthSC/mapperUBO.SampleDistance;\n var tpos: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*minPosSC;\n var tpos2: vec4<f32> = volumeSSBO.values[vNum].SCTCMatrix*(minPosSC + rayStepSC);\n var tstep: vec4<f32> = tpos2 - tpos;\n\n var rayBounds: vec2<f32> = adjustBounds(tpos, tstep, numSteps);\n\n // did we hit anything\n if (rayBounds.x >= rayBounds.y)\n {\n traverseVals[vNum] = vec4<f32>(0.0,0.0,0.0,0.0);\n return;\n }\n\n let ipRange: vec4<f32> = volumeSSBO.values[vNum].ipScalarRange;\n tpos = tpos + tstep*rayBounds.x;\n var curDist: f32 = rayBounds.x;\n var sumVal: f32 = 0.0;\n loop\n {\n var sample: f32 = getTextureValue(vTex, tpos);\n // right now leave filtering off until WebGL changes get merged\n // if (ipRange.z == 0.0 || sample >= ipRange.x && sample <= ipRange.y)\n // {\n sumVal = sumVal + sample;\n // }\n\n // increment position\n curDist = curDist + 1.0;\n tpos = tpos + tstep;\n\n // check if we have reached a terminating condition\n if (curDist > rayBounds.y) { break; }\n }\n\n // process to get the color and opacity\n traverseVals[vNum] = getSimpleColor(sumVal, vNum, cNum);\n}\n\nfn composite(rayLengthSC: f32, minPosSC: vec4<f32>, rayStepSC: vec4<f32>) -> vec4<f32>\n{\n // initial ray position is at the beginning\n var rayPosSC: vec4<f32> = minPosSC;\n\n // how many rows (tfuns) do we have in our tfunTexture\n var tfunRows: f32 = f32(textureDimensions(tfunTexture).y);\n\n var curDist: f32 = 0.0;\n var computedColor: vec4<f32> = vec4<f32>(0.0, 0.0, 0.0, 0.0);\n var sampleColor: vec4<f32>;\n//VTK::Volume::TraverseCalls\n\n loop\n {\n // for each volume, sample and accumulate color\n//VTK::Volume::CompositeCalls\n\n // increment position\n curDist = curDist + mapperUBO.SampleDistance;\n rayPosSC = rayPosSC + rayStepSC;\n\n // check if we have reached a terminating condition\n if (curDist > rayLengthSC) { break; }\n if (computedColor.a > 0.98) { break; }\n }\n return computedColor;\n}\n\n@stage(fragment)\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output: fragmentOutput;\n\n var rayMax: f32 = textureSampleLevel(maxTexture, clampSampler, input.tcoordVS, 0.0).r;\n var rayMin: f32 = textureSampleLevel(minTexture, clampSampler, input.tcoordVS, 0.0).r;\n\n // discard empty rays\n if (rayMax <= rayMin) { discard; }\n else\n {\n // compute start and end ray positions in view coordinates\n var minPosSC: vec4<f32> = rendererUBO.PCSCMatrix*vec4<f32>(2.0 * input.tcoordVS.x - 1.0, 1.0 - 2.0 * input.tcoordVS.y, rayMax, 1.0);\n minPosSC = minPosSC * (1.0 / minPosSC.w);\n var maxPosSC: vec4<f32> = rendererUBO.PCSCMatrix*vec4<f32>(2.0 * input.tcoordVS.x - 1.0, 1.0 - 2.0 * input.tcoordVS.y, rayMin, 1.0);\n maxPosSC = maxPosSC * (1.0 / maxPosSC.w);\n\n var rayLengthSC: f32 = distance(minPosSC.xyz, maxPosSC.xyz);\n var rayStepSC: vec4<f32> = (maxPosSC - minPosSC)*(mapperUBO.SampleDistance/rayLengthSC);\n rayStepSC.w = 0.0;\n\n var computedColor: vec4<f32>;\n\n//VTK::Volume::Loop\n\n//VTK::RenderEncoder::Impl\n }\n\n return output;\n}\n";
13
13
  var tmpMat4 = new Float64Array(16);
14
14
  var tmp2Mat4 = new Float64Array(16); // ----------------------------------------------------------------------------
15
15
  // vtkWebGPUVolumePassFSQ methods
@@ -240,7 +240,9 @@ function vtkWebGPUVolumePassFSQ(publicAPI, model) {
240
240
  //
241
241
 
242
242
  var marray = new Float64Array(model.volumes.length * 16);
243
+ var vPlaneArray = new Float64Array(model.volumes.length * 16);
243
244
  var tstepArray = new Float64Array(model.volumes.length * 4);
245
+ var shadeArray = new Float64Array(model.volumes.length * 4);
244
246
  var spacingArray = new Float64Array(model.volumes.length * 4);
245
247
  var ipScalarRangeArray = new Float64Array(model.volumes.length * 4);
246
248
 
@@ -277,10 +279,20 @@ function vtkWebGPUVolumePassFSQ(publicAPI, model) {
277
279
  marray[vidx * 16 + j] = tmpMat4[j];
278
280
  }
279
281
 
282
+ mat4.invert(tmpMat4, tmpMat4); // now it is Tcoord To SC
283
+
284
+ for (var _j = 0; _j < 4; _j++) {
285
+ vPlaneArray[vidx * 16 + _j * 4] = tmpMat4[_j * 4];
286
+ vPlaneArray[vidx * 16 + _j * 4 + 1] = tmpMat4[_j * 4 + 1];
287
+ vPlaneArray[vidx * 16 + _j * 4 + 2] = tmpMat4[_j * 4 + 2];
288
+ vPlaneArray[vidx * 16 + _j * 4 + 3] = 0.0;
289
+ }
290
+
280
291
  tstepArray[vidx * 4] = 1.0 / dims[0];
281
292
  tstepArray[vidx * 4 + 1] = 1.0 / dims[1];
282
293
  tstepArray[vidx * 4 + 2] = 1.0 / dims[2];
283
294
  tstepArray[vidx * 4 + 3] = 1.0;
295
+ shadeArray[vidx * 4] = actor.getProperty().getShade() ? 1.0 : 0.0;
284
296
 
285
297
  var spacing = _image3.getSpacing();
286
298
 
@@ -299,10 +311,14 @@ function vtkWebGPUVolumePassFSQ(publicAPI, model) {
299
311
  }
300
312
 
301
313
  model.SSBO.addEntry('SCTCMatrix', 'mat4x4<f32>');
314
+ model.SSBO.addEntry('planeNormals', 'mat4x4<f32>');
315
+ model.SSBO.addEntry('shade', 'vec4<f32>');
302
316
  model.SSBO.addEntry('tstep', 'vec4<f32>');
303
317
  model.SSBO.addEntry('spacing', 'vec4<f32>');
304
318
  model.SSBO.addEntry('ipScalarRange', 'vec4<f32>');
305
319
  model.SSBO.setAllInstancesFromArray('SCTCMatrix', marray);
320
+ model.SSBO.setAllInstancesFromArray('planeNormals', vPlaneArray);
321
+ model.SSBO.setAllInstancesFromArray('shade', shadeArray);
306
322
  model.SSBO.setAllInstancesFromArray('tstep', tstepArray);
307
323
  model.SSBO.setAllInstancesFromArray('spacing', spacingArray);
308
324
  model.SSBO.setAllInstancesFromArray('ipScalarRange', ipScalarRangeArray);
@@ -388,7 +388,7 @@ function widgetBehavior(publicAPI, model) {
388
388
  publicAPI.invokeInteractionEvent();
389
389
  }
390
390
 
391
- return model.hasFocus ? macro.EVENT_ABORT : macro.VOID;
391
+ return model.hasFocus || model.isDragging ? macro.EVENT_ABORT : macro.VOID;
392
392
  }; // --------------------------------------------------------------------------
393
393
  // Left click: Add point / End interaction
394
394
  // --------------------------------------------------------------------------
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kitware/vtk.js",
3
- "version": "22.3.0",
3
+ "version": "22.5.0",
4
4
  "description": "Visualization Toolkit for the Web",
5
5
  "keywords": [
6
6
  "3d",