@kitware/vtk.js 27.5.0 → 28.0.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.
Files changed (42) hide show
  1. package/BREAKING_CHANGES.md +4 -0
  2. package/Common/DataModel/Line.d.ts +24 -2
  3. package/Common/DataModel/Line.js +17 -1
  4. package/Common/DataModel/PolyLine.d.ts +36 -2
  5. package/Common/DataModel/PolyLine.js +80 -10
  6. package/Common/Transform/Transform.d.ts +177 -0
  7. package/Common/Transform/Transform.js +81 -3
  8. package/Proxy/Core/View2DProxy.js +22 -12
  9. package/Rendering/Core/AbstractMapper3D.d.ts +1 -3
  10. package/Rendering/Core/AbstractMapper3D.js +21 -45
  11. package/Rendering/Core/ImageCPRMapper.d.ts +380 -0
  12. package/Rendering/Core/ImageCPRMapper.js +361 -0
  13. package/Rendering/OpenGL/ImageCPRMapper.js +919 -0
  14. package/Rendering/OpenGL/Profiles/All.js +1 -0
  15. package/Rendering/OpenGL/Profiles/Volume.js +1 -0
  16. package/Rendering/Profiles/All.js +1 -0
  17. package/Rendering/Profiles/Volume.js +1 -0
  18. package/Widgets/Core/WidgetManager.js +1 -1
  19. package/Widgets/Manipulators/AbstractManipulator.d.ts +2 -2
  20. package/Widgets/Manipulators/CPRManipulator.js +138 -0
  21. package/Widgets/Manipulators/LineManipulator.js +3 -1
  22. package/Widgets/Manipulators/PlaneManipulator.js +3 -1
  23. package/Widgets/Manipulators/TrackballManipulator.js +3 -1
  24. package/Widgets/Widgets3D/AngleWidget/behavior.js +5 -2
  25. package/Widgets/Widgets3D/DistanceWidget/behavior.js +5 -2
  26. package/Widgets/Widgets3D/ImageCroppingWidget/behavior.js +3 -3
  27. package/Widgets/Widgets3D/ImplicitPlaneWidget.js +3 -1
  28. package/Widgets/Widgets3D/LabelWidget/behavior.js +5 -2
  29. package/Widgets/Widgets3D/LineWidget/behavior.js +4 -2
  30. package/Widgets/Widgets3D/PaintWidget/behavior.js +2 -1
  31. package/Widgets/Widgets3D/PolyLineWidget/behavior.js +2 -1
  32. package/Widgets/Widgets3D/ResliceCursorWidget/Constants.js +2 -1
  33. package/Widgets/Widgets3D/ResliceCursorWidget/behavior.js +72 -34
  34. package/Widgets/Widgets3D/ResliceCursorWidget/cprBehavior.js +92 -0
  35. package/Widgets/Widgets3D/ResliceCursorWidget/helpers.js +64 -18
  36. package/Widgets/Widgets3D/ResliceCursorWidget/state.js +30 -16
  37. package/Widgets/Widgets3D/ResliceCursorWidget.js +43 -20
  38. package/Widgets/Widgets3D/ShapeWidget/behavior.js +4 -2
  39. package/Widgets/Widgets3D/SphereWidget/behavior.js +1 -1
  40. package/Widgets/Widgets3D/SplineWidget/behavior.js +3 -1
  41. package/index.d.ts +2 -0
  42. package/package.json +1 -1
@@ -0,0 +1,919 @@
1
+ import _defineProperty from '@babel/runtime/helpers/defineProperty';
2
+ import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
3
+ import macro from '../../macros.js';
4
+ import { mat4, vec3 } from 'gl-matrix';
5
+ import vtkViewNode from '../SceneGraph/ViewNode.js';
6
+ import vtkHelper from './Helper.js';
7
+ import vtkReplacementShaderMapper from './ReplacementShaderMapper.js';
8
+ import vtkShaderProgram from './ShaderProgram.js';
9
+ import vtkOpenGLTexture from './Texture.js';
10
+ import vtkDataArray from '../../Common/Core/DataArray.js';
11
+ import { VtkDataTypes } from '../../Common/Core/DataArray/Constants.js';
12
+ import { Representation } from '../Core/Property/Constants.js';
13
+ import { Filter } from './Texture/Constants.js';
14
+ import { InterpolationType } from '../Core/ImageProperty/Constants.js';
15
+ import { v as vtkPolyDataVS } from './glsl/vtkPolyDataVS.glsl.js';
16
+ import { v as vtkPolyDataFS } from './glsl/vtkPolyDataFS.glsl.js';
17
+ import { registerOverride } from './ViewNodeFactory.js';
18
+
19
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
20
+
21
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
22
+ var vtkErrorMacro = macro.vtkErrorMacro; // ----------------------------------------------------------------------------
23
+ // helper methods
24
+ // ----------------------------------------------------------------------------
25
+
26
+ function computeFnToString(property, fn, numberOfComponents) {
27
+ var pwfun = fn.apply(property);
28
+
29
+ if (pwfun) {
30
+ var iComps = property.getIndependentComponents();
31
+ return "".concat(property.getMTime(), "-").concat(iComps, "-").concat(numberOfComponents);
32
+ }
33
+
34
+ return '0';
35
+ } // ----------------------------------------------------------------------------
36
+ // vtkOpenGLImageCPRMapper methods
37
+ // ----------------------------------------------------------------------------
38
+
39
+
40
+ function vtkOpenGLImageCPRMapper(publicAPI, model) {
41
+ // Set our className
42
+ model.classHierarchy.push('vtkOpenGLImageCPRMapper');
43
+
44
+ publicAPI.buildPass = function (prepass) {
45
+ if (prepass) {
46
+ model.currentRenderPass = null;
47
+ model.openGLImageSlice = publicAPI.getFirstAncestorOfType('vtkOpenGLImageSlice');
48
+ model._openGLRenderer = publicAPI.getFirstAncestorOfType('vtkOpenGLRenderer');
49
+ model._openGLRenderWindow = model._openGLRenderer.getParent();
50
+ model.context = model._openGLRenderWindow.getContext();
51
+ model.openGLCamera = model._openGLRenderer.getViewNodeFor(model._openGLRenderer.getRenderable().getActiveCamera());
52
+ model.tris.setOpenGLRenderWindow(model._openGLRenderWindow);
53
+ model.volumeTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
54
+ model.colorTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
55
+ model.pwfTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
56
+ }
57
+ };
58
+
59
+ publicAPI.opaquePass = function (prepass, renderPass) {
60
+ if (prepass) {
61
+ model.currentRenderPass = renderPass;
62
+ publicAPI.render();
63
+ }
64
+ };
65
+
66
+ publicAPI.opaqueZBufferPass = function (prepass) {
67
+ if (prepass) {
68
+ model.haveSeenDepthRequest = true;
69
+ model.renderDepth = true;
70
+ publicAPI.render();
71
+ model.renderDepth = false;
72
+ }
73
+ };
74
+
75
+ publicAPI.getCoincidentParameters = function (ren, actor) {
76
+ if (model.renderable.getResolveCoincidentTopology()) {
77
+ return model.renderable.getCoincidentTopologyPolygonOffsetParameters();
78
+ }
79
+
80
+ return null;
81
+ };
82
+
83
+ publicAPI.render = function () {
84
+ var prop = model.openGLImageSlice.getRenderable();
85
+
86
+ var ren = model._openGLRenderer.getRenderable();
87
+
88
+ publicAPI.renderPiece(ren, prop);
89
+ };
90
+
91
+ publicAPI.renderPiece = function (ren, prop) {
92
+ publicAPI.invokeEvent({
93
+ type: 'StartEvent'
94
+ });
95
+ model.renderable.update();
96
+ publicAPI.invokeEvent({
97
+ type: 'EndEvent'
98
+ }); // Check if the ImageCPRMapper has everything it needs to render
99
+
100
+ if (!model.renderable.preRenderCheck()) {
101
+ return;
102
+ }
103
+
104
+ model.currentImageDataInput = model.renderable.getInputData(0);
105
+ model.currentCenterlineInput = model.renderable.getOrientedCenterline();
106
+ publicAPI.renderPieceStart(ren, prop);
107
+ publicAPI.renderPieceDraw(ren, prop);
108
+ publicAPI.renderPieceFinish(ren, prop);
109
+ };
110
+
111
+ publicAPI.renderPieceStart = function (ren, actor) {
112
+ // make sure the BOs are up to date
113
+ publicAPI.updateBufferObjects(ren, actor);
114
+ };
115
+
116
+ publicAPI.renderPieceDraw = function (ren, actor) {
117
+ var gl = model.context; // activate the texture
118
+
119
+ model.volumeTexture.activate();
120
+ model.colorTexture.activate();
121
+ model.pwfTexture.activate(); // draw polygons
122
+
123
+ if (model.tris.getCABO().getElementCount()) {
124
+ // First we do the triangles, update the shader, set uniforms, etc.
125
+ publicAPI.updateShaders(model.tris, ren, actor);
126
+ gl.drawArrays(gl.TRIANGLES, 0, model.tris.getCABO().getElementCount());
127
+ model.tris.getVAO().release();
128
+ }
129
+
130
+ model.volumeTexture.deactivate();
131
+ model.colorTexture.deactivate();
132
+ model.pwfTexture.deactivate();
133
+ };
134
+
135
+ publicAPI.renderPieceFinish = function (ren, actor) {};
136
+
137
+ publicAPI.updateBufferObjects = function (ren, actor) {
138
+ // Rebuild buffers if needed
139
+ if (publicAPI.getNeedToRebuildBufferObjects(ren, actor)) {
140
+ publicAPI.buildBufferObjects(ren, actor);
141
+ }
142
+ };
143
+
144
+ publicAPI.getNeedToRebuildBufferObjects = function (ren, actor) {
145
+ // first do a coarse check
146
+ // Note that the actor's mtime includes it's properties mtime
147
+ var vmtime = model.VBOBuildTime.getMTime();
148
+
149
+ if (vmtime < publicAPI.getMTime() || vmtime < model.renderable.getMTime() || vmtime < actor.getMTime() || vmtime < model.currentImageDataInput.getMTime() || vmtime < model.currentCenterlineInput.getMTime()) {
150
+ return true;
151
+ }
152
+
153
+ return false;
154
+ };
155
+
156
+ publicAPI.buildBufferObjects = function (ren, actor) {
157
+ var image = model.currentImageDataInput;
158
+ var centerline = model.currentCenterlineInput;
159
+ var actorProperty = actor.getProperty(); // Set interpolation on the texture based on property setting
160
+
161
+ if (actorProperty.getInterpolationType() === InterpolationType.NEAREST) {
162
+ model.volumeTexture.setMinificationFilter(Filter.NEAREST);
163
+ model.volumeTexture.setMagnificationFilter(Filter.NEAREST);
164
+ model.colorTexture.setMinificationFilter(Filter.NEAREST);
165
+ model.colorTexture.setMagnificationFilter(Filter.NEAREST);
166
+ model.pwfTexture.setMinificationFilter(Filter.NEAREST);
167
+ model.pwfTexture.setMagnificationFilter(Filter.NEAREST);
168
+ } else {
169
+ model.volumeTexture.setMinificationFilter(Filter.LINEAR);
170
+ model.volumeTexture.setMagnificationFilter(Filter.LINEAR);
171
+ model.colorTexture.setMinificationFilter(Filter.LINEAR);
172
+ model.colorTexture.setMagnificationFilter(Filter.LINEAR);
173
+ model.pwfTexture.setMinificationFilter(Filter.LINEAR);
174
+ model.pwfTexture.setMagnificationFilter(Filter.LINEAR);
175
+ } // Rebuild the volumeTexture if the data has changed
176
+
177
+
178
+ var imageTime = image.getMTime();
179
+
180
+ if (model.volumeTextureTime !== imageTime) {
181
+ // Build the textures
182
+ var dims = image.getDimensions();
183
+
184
+ var _scalars = image.getPointData().getScalars();
185
+
186
+ if (!_scalars) {
187
+ return;
188
+ } // Use norm16 for scalar texture if the extension is available
189
+
190
+
191
+ model.volumeTexture.setOglNorm16Ext(model.context.getExtension('EXT_texture_norm16'));
192
+ model.volumeTexture.releaseGraphicsResources(model._openGLRenderWindow);
193
+ model.volumeTexture.resetFormatAndType();
194
+ model.volumeTexture.create3DFilterableFromRaw(dims[0], dims[1], dims[2], _scalars.getNumberOfComponents(), _scalars.getDataType(), _scalars.getData(), model.renderable.getPreferSizeOverAccuracy());
195
+ model.volumeTextureTime = imageTime;
196
+ } // Rebuild the color texture if needed
197
+
198
+
199
+ var scalars = image.getPointData() && image.getPointData().getScalars();
200
+
201
+ if (!scalars) {
202
+ return;
203
+ }
204
+
205
+ var numComp = scalars.getNumberOfComponents();
206
+ var ppty = actor.getProperty();
207
+ var iComps = ppty.getIndependentComponents();
208
+ var numIComps = iComps ? numComp : 1;
209
+ var textureHeight = iComps ? 2 * numIComps : 1;
210
+ var cfunToString = computeFnToString(ppty, ppty.getRGBTransferFunction, numIComps);
211
+
212
+ if (model.colorTextureString !== cfunToString) {
213
+ var cWidth = 1024;
214
+ var cSize = cWidth * textureHeight * 3;
215
+ var cTable = new Uint8Array(cSize);
216
+ var cfun = ppty.getRGBTransferFunction();
217
+
218
+ if (cfun) {
219
+ var tmpTable = new Float32Array(cWidth * 3);
220
+
221
+ for (var c = 0; c < numIComps; c++) {
222
+ cfun = ppty.getRGBTransferFunction(c);
223
+ var cRange = cfun.getRange();
224
+ cfun.getTable(cRange[0], cRange[1], cWidth, tmpTable, 1);
225
+
226
+ if (iComps) {
227
+ for (var i = 0; i < cWidth * 3; i++) {
228
+ cTable[c * cWidth * 6 + i] = 255.0 * tmpTable[i];
229
+ cTable[c * cWidth * 6 + i + cWidth * 3] = 255.0 * tmpTable[i];
230
+ }
231
+ } else {
232
+ for (var _i = 0; _i < cWidth * 3; _i++) {
233
+ cTable[c * cWidth * 6 + _i] = 255.0 * tmpTable[_i];
234
+ }
235
+ }
236
+ }
237
+
238
+ model.colorTexture.releaseGraphicsResources(model._openGLRenderWindow);
239
+ model.colorTexture.resetFormatAndType();
240
+ model.colorTexture.create2DFromRaw(cWidth, textureHeight, 3, VtkDataTypes.UNSIGNED_CHAR, cTable);
241
+ } else {
242
+ for (var _i2 = 0; _i2 < cWidth * 3; ++_i2) {
243
+ cTable[_i2] = 255.0 * _i2 / ((cWidth - 1) * 3);
244
+ cTable[_i2 + 1] = 255.0 * _i2 / ((cWidth - 1) * 3);
245
+ cTable[_i2 + 2] = 255.0 * _i2 / ((cWidth - 1) * 3);
246
+ }
247
+
248
+ model.colorTexture.create2DFromRaw(cWidth, 1, 3, VtkDataTypes.UNSIGNED_CHAR, cTable);
249
+ }
250
+
251
+ model.colorTextureString = cfunToString;
252
+ } // Build piecewise function buffer. This buffer is used either
253
+ // for component weighting or opacity, depending on whether we're
254
+ // rendering components independently or not.
255
+
256
+
257
+ var pwfunToString = computeFnToString(ppty, ppty.getPiecewiseFunction, numIComps);
258
+
259
+ if (model.pwfTextureString !== pwfunToString) {
260
+ var pwfWidth = 1024;
261
+ var pwfSize = pwfWidth * textureHeight;
262
+ var pwfTable = new Uint8Array(pwfSize);
263
+ var pwfun = ppty.getPiecewiseFunction(); // support case where pwfun is added/removed
264
+
265
+ model.pwfTexture.releaseGraphicsResources(model._openGLRenderWindow);
266
+ model.pwfTexture.resetFormatAndType();
267
+
268
+ if (pwfun) {
269
+ var pwfFloatTable = new Float32Array(pwfSize);
270
+
271
+ var _tmpTable = new Float32Array(pwfWidth);
272
+
273
+ for (var _c = 0; _c < numIComps; ++_c) {
274
+ pwfun = ppty.getPiecewiseFunction(_c);
275
+
276
+ if (pwfun === null) {
277
+ // Piecewise constant max if no function supplied for this component
278
+ pwfFloatTable.fill(1.0);
279
+ } else {
280
+ var pwfRange = pwfun.getRange();
281
+ pwfun.getTable(pwfRange[0], pwfRange[1], pwfWidth, _tmpTable, 1); // adjust for sample distance etc
282
+
283
+ if (iComps) {
284
+ for (var _i3 = 0; _i3 < pwfWidth; _i3++) {
285
+ pwfFloatTable[_c * pwfWidth * 2 + _i3] = _tmpTable[_i3];
286
+ pwfFloatTable[_c * pwfWidth * 2 + _i3 + pwfWidth] = _tmpTable[_i3];
287
+ }
288
+ } else {
289
+ for (var _i4 = 0; _i4 < pwfWidth; _i4++) {
290
+ pwfFloatTable[_c * pwfWidth * 2 + _i4] = _tmpTable[_i4];
291
+ }
292
+ }
293
+ }
294
+ }
295
+
296
+ model.pwfTexture.create2DFromRaw(pwfWidth, textureHeight, 1, VtkDataTypes.FLOAT, pwfFloatTable);
297
+ } else {
298
+ // default is opaque
299
+ pwfTable.fill(255.0);
300
+ model.pwfTexture.create2DFromRaw(pwfWidth, 1, 1, VtkDataTypes.UNSIGNED_CHAR, pwfTable);
301
+ }
302
+
303
+ model.pwfTextureString = pwfunToString;
304
+ } // Rebuild the image vertices if needed
305
+
306
+
307
+ if (model.VBOBuildTime.getMTime() < model.renderable.getMTime() || model.VBOBuildTime.getMTime() < centerline.getMTime()) {
308
+ var nPoints = centerline.getNumberOfPoints();
309
+ var nLines = nPoints <= 1 ? 0 : nPoints - 1;
310
+ var distances = centerline.getDistancesToFirstPoint();
311
+ var totalHeight = model.renderable.getHeight();
312
+ var nPts = 4 * nLines; // Create the array of point: 4 points per segment
313
+
314
+ var ptsArray = new Float32Array(3 * nPts);
315
+ var widthMC = model.renderable.getWidth();
316
+
317
+ for (var lineIdx = 0, offset = 0; lineIdx < nLines; ++lineIdx) {
318
+ // Use model coordinates
319
+ // See "setCameraShaderParameters" to see how MCPCMatrix is built
320
+ // Top left
321
+ ptsArray.set([0, totalHeight - distances[lineIdx], 0], offset);
322
+ offset += 3; // Top right
323
+
324
+ ptsArray.set([widthMC, totalHeight - distances[lineIdx], 0], offset);
325
+ offset += 3; // Bottom right
326
+
327
+ ptsArray.set([widthMC, totalHeight - distances[lineIdx + 1], 0], offset);
328
+ offset += 3; // Bottom left
329
+
330
+ ptsArray.set([0, totalHeight - distances[lineIdx + 1], 0], offset);
331
+ offset += 3;
332
+ }
333
+
334
+ var points = vtkDataArray.newInstance({
335
+ numberOfComponents: 3,
336
+ values: ptsArray
337
+ });
338
+ points.setName('points'); // Create the array of cells: a quad per segment
339
+
340
+ var cellArray = new Uint16Array(5 * nLines);
341
+
342
+ for (var _lineIdx = 0, _offset = 0, ptIdx = 0; _lineIdx < nLines; ++_lineIdx) {
343
+ cellArray.set([4, ptIdx + 3, ptIdx + 2, ptIdx + 1, ptIdx], _offset);
344
+ _offset += 5;
345
+ ptIdx += 4;
346
+ }
347
+
348
+ var cells = vtkDataArray.newInstance({
349
+ numberOfComponents: 1,
350
+ values: cellArray
351
+ }); // Create the array of centerline positions (VBO custom attribute)
352
+
353
+ var pointsDataArray = centerline.getPoints();
354
+ var centerlinePositionArray = new Float32Array(3 * nPts);
355
+ var pa = new Array(3);
356
+ var pb = new Array(3);
357
+
358
+ for (var _lineIdx2 = 0, _offset2 = 0; _lineIdx2 < nLines; ++_lineIdx2) {
359
+ pointsDataArray.getPoint(_lineIdx2, pa);
360
+ pointsDataArray.getPoint(_lineIdx2 + 1, pb); // Top left
361
+
362
+ centerlinePositionArray.set(pa, _offset2);
363
+ _offset2 += 3; // Top right
364
+
365
+ centerlinePositionArray.set(pa, _offset2);
366
+ _offset2 += 3; // Bottom right
367
+
368
+ centerlinePositionArray.set(pb, _offset2);
369
+ _offset2 += 3; // Bottom left
370
+
371
+ centerlinePositionArray.set(pb, _offset2);
372
+ _offset2 += 3;
373
+ }
374
+
375
+ var centerlinePosition = vtkDataArray.newInstance({
376
+ numberOfComponents: 3,
377
+ values: centerlinePositionArray,
378
+ name: 'centerlinePosition'
379
+ }); // Create the array of quad index:
380
+ // 0 ____ 1
381
+ // | |
382
+ // |____|
383
+ // 2 3
384
+
385
+ var quadIndexArray = new Float32Array(nPts);
386
+
387
+ for (var _lineIdx3 = 0, _offset3 = 0; _lineIdx3 < nLines; ++_lineIdx3) {
388
+ quadIndexArray.set([0, // Top left
389
+ 1, // Top right
390
+ 3, // Bottom right
391
+ 2 // Bottom left
392
+ ], _offset3);
393
+ _offset3 += 4;
394
+ }
395
+
396
+ var quadIndex = vtkDataArray.newInstance({
397
+ numberOfComponents: 1,
398
+ values: quadIndexArray,
399
+ name: 'quadIndex'
400
+ });
401
+ var customAttributes = [centerlinePosition, quadIndex];
402
+
403
+ if (!model.renderable.getUseUniformOrientation()) {
404
+ // For each {quad / centerline segment}, two vectors in directionDataArray give the orientation of the centerline
405
+ // Send these two vectors to each vertex and use flat interpolation to get them as is in the fragment shader
406
+ // The interpolation will occur in the fragment shader (slerp)
407
+ var directions = model.renderable.getCenterlineTangentDirections();
408
+ var centerlineTopDirectionArray = new Float32Array(3 * nPts);
409
+ var centerlineBotDirectionArray = new Float32Array(3 * nPts);
410
+
411
+ for (var _lineIdx4 = 0, _offset4 = 0; _lineIdx4 < nLines; ++_lineIdx4) {
412
+ var baseDirectionIdx = 3 * _lineIdx4; // Every vertex of each quad/segment have the same topDir and botDir
413
+ // Top left, Top right, Bottom right, Bottom left
414
+
415
+ for (var _i5 = 0; _i5 < 4; ++_i5) {
416
+ // Top array
417
+ centerlineTopDirectionArray[_offset4 + 0] = directions[baseDirectionIdx + 0];
418
+ centerlineTopDirectionArray[_offset4 + 1] = directions[baseDirectionIdx + 1];
419
+ centerlineTopDirectionArray[_offset4 + 2] = directions[baseDirectionIdx + 2]; // Bot array
420
+
421
+ centerlineBotDirectionArray[_offset4 + 0] = directions[baseDirectionIdx + 3];
422
+ centerlineBotDirectionArray[_offset4 + 1] = directions[baseDirectionIdx + 4];
423
+ centerlineBotDirectionArray[_offset4 + 2] = directions[baseDirectionIdx + 5];
424
+ _offset4 += 3;
425
+ }
426
+ }
427
+
428
+ var centerlineTopDirection = vtkDataArray.newInstance({
429
+ numberOfComponents: 3,
430
+ values: centerlineTopDirectionArray,
431
+ name: 'centerlineTopDirection'
432
+ });
433
+ var centerlineBotDirection = vtkDataArray.newInstance({
434
+ numberOfComponents: 3,
435
+ values: centerlineBotDirectionArray,
436
+ name: 'centerlineBotDirection'
437
+ });
438
+ customAttributes.push(centerlineTopDirection, centerlineBotDirection);
439
+ }
440
+
441
+ model.tris.getCABO().createVBO(cells, 'polys', Representation.SURFACE, {
442
+ points: points,
443
+ customAttributes: customAttributes
444
+ });
445
+ model.VBOBuildTime.modified();
446
+ }
447
+ };
448
+
449
+ publicAPI.getNeedToRebuildShaders = function (cellBO, ren, actor) {
450
+ // has something changed that would require us to recreate the shader?
451
+ // candidates are
452
+ // property modified (representation interpolation and lighting)
453
+ // input modified
454
+ // light complexity changed
455
+ // render pass shader replacement changed
456
+ var tNumComp = model.volumeTexture.getComponents();
457
+ var iComp = actor.getProperty().getIndependentComponents();
458
+
459
+ if (model.lastHaveSeenDepthRequest !== model.haveSeenDepthRequest || cellBO.getProgram() === 0 || model.lastTextureComponents !== tNumComp || model.lastIndependentComponents !== iComp) {
460
+ model.lastHaveSeenDepthRequest = model.haveSeenDepthRequest;
461
+ model.lastTextureComponents = tNumComp;
462
+ model.lastIndependentComponents = iComp;
463
+ return true;
464
+ }
465
+
466
+ return false;
467
+ };
468
+
469
+ publicAPI.buildShaders = function (shaders, ren, actor) {
470
+ publicAPI.getShaderTemplate(shaders, ren, actor);
471
+ publicAPI.replaceShaderValues(shaders, ren, actor);
472
+ };
473
+
474
+ publicAPI.replaceShaderValues = function (shaders, ren, actor) {
475
+ var VSSource = shaders.Vertex;
476
+ var FSSource = shaders.Fragment; // Vertex shader main replacements
477
+
478
+ VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::Camera::Dec', ['uniform mat4 MCPCMatrix;']).result;
479
+ VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::PositionVC::Impl', [' gl_Position = MCPCMatrix * vertexMC;']).result;
480
+ var vsColorDec = ['attribute vec3 centerlinePosition;', 'attribute float quadIndex;', 'uniform float width;', 'out vec2 quadOffsetVSOutput;', 'out vec3 centerlinePosVSOutput;'];
481
+ var isDirectionUniform = model.renderable.getUseUniformOrientation();
482
+
483
+ if (isDirectionUniform) {
484
+ vsColorDec.push('out vec3 centerlineDirVSOutput;', 'uniform vec3 centerlineDirection;');
485
+ } else {
486
+ vsColorDec.push('out vec3 centerlineTopDirVSOutput;', 'out vec3 centerlineBotDirVSOutput;', 'out float centerlineAngleVSOutput;', 'attribute vec3 centerlineTopDirection;', 'attribute vec3 centerlineBotDirection;');
487
+ }
488
+
489
+ VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::Color::Dec', vsColorDec).result;
490
+ var vsColorImpl = [// quadOffsetVSOutput.x: left = -0.5* width; right = 0.5 * width
491
+ // quadOffsetVSOutput.y: bottom = 0.0; top = 1.0;
492
+ 'quadOffsetVSOutput = vec2(width * (mod(quadIndex, 2.0) == 0.0 ? -0.5 : 0.5), quadIndex > 1.0 ? 0.0 : 1.0);', 'centerlinePosVSOutput = centerlinePosition;'];
493
+
494
+ if (isDirectionUniform) {
495
+ vsColorImpl.push('centerlineDirVSOutput = centerlineDirection;');
496
+ } else {
497
+ vsColorImpl.push( // When u and v are unit vectors: uvAngle = 2 * atan2(|| u - v ||, || u + v ||)
498
+ // When u != -v: || u + v || > 0
499
+ // When x > 0: atan2(y, x) = atan(y/x)
500
+ // Thus: dirAngle = 2 * atan(|| topDir - botDir || / || topDir + botDir ||)
501
+ // This is more stable and should not be to slow compared to acos(dot(u, v))
502
+ 'vec3 sumVec = centerlineTopDirection + centerlineBotDirection;', 'float sumLen2 = dot(sumVec, sumVec);', 'float diffLen2 = 4.0 - sumLen2;', 'if (diffLen2 < 0.001) {', ' // vectors are too close to each other, use lerp', ' centerlineAngleVSOutput = -1.0; // use negative angle as a flag for lerp', ' centerlineTopDirVSOutput = centerlineTopDirection;', ' centerlineBotDirVSOutput = centerlineBotDirection;', '} else if (sumLen2 == 0.0) {', " // vector are opposite to each other, don't make a choice for the user", ' // use slerp without direction, it will display the centerline color on each row of pixel', ' centerlineAngleVSOutput = 0.0;', ' centerlineTopDirVSOutput = vec3(0.0);', ' centerlineBotDirVSOutput = vec3(0.0);', '} else {', ' // use slerp', ' centerlineAngleVSOutput = 2.0 * atan(sqrt(diffLen2/sumLen2));', ' float sinAngle = sin(centerlineAngleVSOutput);', ' centerlineTopDirVSOutput = centerlineTopDirection / sinAngle;', ' centerlineBotDirVSOutput = centerlineBotDirection / sinAngle;', '}');
503
+ }
504
+
505
+ VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::Color::Impl', vsColorImpl).result; // Fragment shader main replacements
506
+
507
+ var tNumComp = model.volumeTexture.getComponents();
508
+ var iComps = actor.getProperty().getIndependentComponents();
509
+ var tcoordFSDec = [// used to compute texture coordinates of the sample
510
+ 'uniform mat4 MCTCMatrix; // Model coordinates to texture coordinates', 'in vec2 quadOffsetVSOutput;', 'in vec3 centerlinePosVSOutput;', // volume texture
511
+ 'uniform highp sampler3D volumeTexture;', // color and pwf textures
512
+ 'uniform sampler2D colorTexture1;', 'uniform sampler2D pwfTexture1;', // opacity
513
+ 'uniform float opacity;', // background color (out of volume samples)
514
+ 'uniform vec4 backgroundColor;', // color shift and scale
515
+ "uniform float cshift0;", "uniform float cscale0;", // weighting shift and scale
516
+ "uniform float pwfshift0;", "uniform float pwfscale0;"];
517
+
518
+ if (isDirectionUniform) {
519
+ tcoordFSDec.push('in vec3 centerlineDirVSOutput;');
520
+ } else {
521
+ tcoordFSDec.push('in vec3 centerlineTopDirVSOutput;', 'in vec3 centerlineBotDirVSOutput;', 'in float centerlineAngleVSOutput;');
522
+ }
523
+
524
+ if (iComps) {
525
+ for (var comp = 1; comp < tNumComp; comp++) {
526
+ tcoordFSDec = tcoordFSDec.concat([// color shift and scale
527
+ "uniform float cshift".concat(comp, ";"), "uniform float cscale".concat(comp, ";"), // weighting shift and scale
528
+ "uniform float pwfshift".concat(comp, ";"), "uniform float pwfscale".concat(comp, ";")]);
529
+ } // the heights defined below are the locations
530
+ // for the up to four components of the tfuns
531
+ // the tfuns have a height of 2XnumComps pixels so the
532
+ // values are computed to hit the middle of the two rows
533
+ // for that component
534
+
535
+
536
+ switch (tNumComp) {
537
+ case 1:
538
+ tcoordFSDec = tcoordFSDec.concat(['uniform float mix0;', '#define height0 0.5']);
539
+ break;
540
+
541
+ case 2:
542
+ tcoordFSDec = tcoordFSDec.concat(['uniform float mix0;', 'uniform float mix1;', '#define height0 0.25', '#define height1 0.75']);
543
+ break;
544
+
545
+ case 3:
546
+ tcoordFSDec = tcoordFSDec.concat(['uniform float mix0;', 'uniform float mix1;', 'uniform float mix2;', '#define height0 0.17', '#define height1 0.5', '#define height2 0.83']);
547
+ break;
548
+
549
+ case 4:
550
+ tcoordFSDec = tcoordFSDec.concat(['uniform float mix0;', 'uniform float mix1;', 'uniform float mix2;', 'uniform float mix3;', '#define height0 0.125', '#define height1 0.375', '#define height2 0.625', '#define height3 0.875']);
551
+ break;
552
+
553
+ default:
554
+ vtkErrorMacro('Unsupported number of independent coordinates.');
555
+ }
556
+ }
557
+
558
+ FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::TCoord::Dec', tcoordFSDec).result;
559
+ var tcoordFSImpl = [];
560
+
561
+ if (isDirectionUniform) {
562
+ tcoordFSImpl.push('vec3 interpolatedCenterlineDir = centerlineDirVSOutput;');
563
+ } else {
564
+ // Slerp or lerp between centerlineTopDirVSOutput and centerlineBotDirVSOutput
565
+ // We use quadOffsetVSOutput.y: bottom = 0.0; top = 1.0;
566
+ tcoordFSImpl.push('vec3 interpolatedCenterlineDir;', 'if (centerlineAngleVSOutput < 0.0) {', ' // Lerp', ' interpolatedCenterlineDir = quadOffsetVSOutput.y * centerlineTopDirVSOutput + (1.0 - quadOffsetVSOutput.y) * centerlineBotDirVSOutput;', '} else {', ' // Slerp', ' float topInterpolationAngle = quadOffsetVSOutput.y * centerlineAngleVSOutput;', ' float botInterpolationAngle = centerlineAngleVSOutput - topInterpolationAngle;', ' interpolatedCenterlineDir = sin(topInterpolationAngle) * centerlineTopDirVSOutput + sin(botInterpolationAngle) * centerlineBotDirVSOutput;', '}', '// Slerp should give a normalized vector but when sin(angle) is small, rounding error occurs', '// Normalize for both lerp and slerp', 'interpolatedCenterlineDir = normalize(interpolatedCenterlineDir);');
567
+ }
568
+
569
+ tcoordFSImpl.push('vec3 volumePosMC = centerlinePosVSOutput + quadOffsetVSOutput.x * interpolatedCenterlineDir;', 'vec3 volumePosTC = (MCTCMatrix * vec4(volumePosMC, 1.0)).xyz;', 'if (any(lessThan(volumePosTC, vec3(0.0))) || any(greaterThan(volumePosTC, vec3(1.0))))', '{', ' // set the background color and exit', ' gl_FragData[0] = backgroundColor;', ' return;', '}', 'vec4 tvalue = texture(volumeTexture, volumePosTC);');
570
+
571
+ if (iComps) {
572
+ var rgba = ['r', 'g', 'b', 'a'];
573
+
574
+ for (var _comp = 0; _comp < tNumComp; ++_comp) {
575
+ tcoordFSImpl = tcoordFSImpl.concat(["vec3 tcolor".concat(_comp, " = mix").concat(_comp, " * texture2D(colorTexture1, vec2(tvalue.").concat(rgba[_comp], " * cscale").concat(_comp, " + cshift").concat(_comp, ", height").concat(_comp, ")).rgb;"), "float compWeight".concat(_comp, " = mix").concat(_comp, " * texture2D(pwfTexture1, vec2(tvalue.").concat(rgba[_comp], " * pwfscale").concat(_comp, " + pwfshift").concat(_comp, ", height").concat(_comp, ")).r;")]);
576
+ }
577
+
578
+ switch (tNumComp) {
579
+ case 1:
580
+ tcoordFSImpl = tcoordFSImpl.concat(['gl_FragData[0] = vec4(tcolor0.rgb, compWeight0 * opacity);']);
581
+ break;
582
+
583
+ case 2:
584
+ tcoordFSImpl = tcoordFSImpl.concat(['float weightSum = compWeight0 + compWeight1;', 'gl_FragData[0] = vec4(vec3((tcolor0.rgb * (compWeight0 / weightSum)) + (tcolor1.rgb * (compWeight1 / weightSum))), opacity);']);
585
+ break;
586
+
587
+ case 3:
588
+ tcoordFSImpl = tcoordFSImpl.concat(['float weightSum = compWeight0 + compWeight1 + compWeight2;', 'gl_FragData[0] = vec4(vec3((tcolor0.rgb * (compWeight0 / weightSum)) + (tcolor1.rgb * (compWeight1 / weightSum)) + (tcolor2.rgb * (compWeight2 / weightSum))), opacity);']);
589
+ break;
590
+
591
+ case 4:
592
+ tcoordFSImpl = tcoordFSImpl.concat(['float weightSum = compWeight0 + compWeight1 + compWeight2 + compWeight3;', 'gl_FragData[0] = vec4(vec3((tcolor0.rgb * (compWeight0 / weightSum)) + (tcolor1.rgb * (compWeight1 / weightSum)) + (tcolor2.rgb * (compWeight2 / weightSum)) + (tcolor3.rgb * (compWeight3 / weightSum))), opacity);']);
593
+ break;
594
+
595
+ default:
596
+ vtkErrorMacro('Unsupported number of independent coordinates.');
597
+ }
598
+ } else {
599
+ // dependent components
600
+ switch (tNumComp) {
601
+ case 1:
602
+ tcoordFSImpl = tcoordFSImpl.concat(['// Dependent components', 'float intensity = tvalue.r;', 'vec3 tcolor = texture2D(colorTexture1, vec2(intensity * cscale0 + cshift0, 0.5)).rgb;', 'float scalarOpacity = texture2D(pwfTexture1, vec2(intensity * pwfscale0 + pwfshift0, 0.5)).r;', 'gl_FragData[0] = vec4(tcolor, scalarOpacity * opacity);']);
603
+ break;
604
+
605
+ case 2:
606
+ tcoordFSImpl = tcoordFSImpl.concat(['float intensity = tvalue.r*cscale0 + cshift0;', 'gl_FragData[0] = vec4(texture2D(colorTexture1, vec2(intensity, 0.5)).rgb, pwfscale0*tvalue.g + pwfshift0);']);
607
+ break;
608
+
609
+ case 3:
610
+ tcoordFSImpl = tcoordFSImpl.concat(['vec4 tcolor = cscale0*tvalue + cshift0;', 'gl_FragData[0] = vec4(texture2D(colorTexture1, vec2(tcolor.r,0.5)).r,', ' texture2D(colorTexture1, vec2(tcolor.g,0.5)).r,', ' texture2D(colorTexture1, vec2(tcolor.b,0.5)).r, opacity);']);
611
+ break;
612
+
613
+ default:
614
+ tcoordFSImpl = tcoordFSImpl.concat(['vec4 tcolor = cscale0*tvalue + cshift0;', 'gl_FragData[0] = vec4(texture2D(colorTexture1, vec2(tcolor.r,0.5)).r,', ' texture2D(colorTexture1, vec2(tcolor.g,0.5)).r,', ' texture2D(colorTexture1, vec2(tcolor.b,0.5)).r, tcolor.a);']);
615
+ }
616
+ }
617
+
618
+ FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::TCoord::Impl', tcoordFSImpl).result; // Picking shader replacements
619
+
620
+ if (model.haveSeenDepthRequest) {
621
+ FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::ZBuffer::Dec', 'uniform int depthRequest;').result;
622
+ FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::ZBuffer::Impl', ['if (depthRequest == 1) {', 'float iz = floor(gl_FragCoord.z*65535.0 + 0.1);', 'float rf = floor(iz/256.0)/255.0;', 'float gf = mod(iz,256.0)/255.0;', 'gl_FragData[0] = vec4(rf, gf, 0.0, 1.0); }']).result;
623
+ }
624
+
625
+ shaders.Vertex = VSSource;
626
+ shaders.Fragment = FSSource;
627
+ publicAPI.replaceShaderClip(shaders, ren, actor);
628
+ publicAPI.replaceShaderCoincidentOffset(shaders, ren, actor);
629
+ };
630
+
631
+ publicAPI.replaceShaderClip = function (shaders, ren, actor) {
632
+ var VSSource = shaders.Vertex;
633
+ var FSSource = shaders.Fragment;
634
+
635
+ if (model.renderable.getNumberOfClippingPlanes()) {
636
+ var numClipPlanes = model.renderable.getNumberOfClippingPlanes();
637
+
638
+ if (numClipPlanes > 6) {
639
+ macro.vtkErrorMacro('OpenGL has a limit of 6 clipping planes');
640
+ numClipPlanes = 6;
641
+ }
642
+
643
+ VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::Clip::Dec', ['uniform int numClipPlanes;', 'uniform vec4 clipPlanes[6];', 'varying float clipDistancesVSOutput[6];']).result;
644
+ VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::Clip::Impl', ['for (int planeNum = 0; planeNum < 6; planeNum++)', ' {', ' if (planeNum >= numClipPlanes)', ' {', ' break;', ' }', ' clipDistancesVSOutput[planeNum] = dot(clipPlanes[planeNum], vertexMC);', ' }']).result;
645
+ FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Clip::Dec', ['uniform int numClipPlanes;', 'varying float clipDistancesVSOutput[6];']).result;
646
+ FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Clip::Impl', ['for (int planeNum = 0; planeNum < 6; planeNum++)', ' {', ' if (planeNum >= numClipPlanes)', ' {', ' break;', ' }', ' if (clipDistancesVSOutput[planeNum] < 0.0) discard;', ' }']).result;
647
+ }
648
+
649
+ shaders.Vertex = VSSource;
650
+ shaders.Fragment = FSSource;
651
+ };
652
+
653
+ publicAPI.getShaderTemplate = function (shaders, ren, actor) {
654
+ shaders.Vertex = vtkPolyDataVS;
655
+ shaders.Fragment = vtkPolyDataFS;
656
+ shaders.Geometry = '';
657
+ };
658
+
659
+ publicAPI.setMapperShaderParameters = function (cellBO, ren, actor) {
660
+ var _cellBO$getProgram;
661
+
662
+ if (cellBO.getCABO().getElementCount() && (model.VBOBuildTime.getMTime() > cellBO.getAttributeUpdateTime().getMTime() || cellBO.getShaderSourceTime().getMTime() > cellBO.getAttributeUpdateTime().getMTime())) {
663
+ if (cellBO.getProgram().isAttributeUsed('vertexMC')) {
664
+ if (!cellBO.getVAO().addAttributeArray(cellBO.getProgram(), cellBO.getCABO(), 'vertexMC', cellBO.getCABO().getVertexOffset(), cellBO.getCABO().getStride(), model.context.FLOAT, 3, model.context.FALSE)) {
665
+ vtkErrorMacro('Error setting vertexMC in shader VAO.');
666
+ }
667
+ } // Custom data of the CABO (centerlinePosition, centerlineTopDirection,
668
+ // centerlineBotDirection, quadIndex and user defined custom data)
669
+
670
+
671
+ cellBO.getCABO().getCustomData().forEach(function (data) {
672
+ if (data && cellBO.getProgram().isAttributeUsed(data.name) && !cellBO.getVAO().addAttributeArray(cellBO.getProgram(), cellBO.getCABO(), data.name, data.offset, cellBO.getCABO().getStride(), model.context.FLOAT, data.components, model.context.FALSE)) {
673
+ vtkErrorMacro("Error setting ".concat(data.name, " in shader VAO."));
674
+ }
675
+ });
676
+ cellBO.getAttributeUpdateTime().modified();
677
+ }
678
+
679
+ var texUnit = model.volumeTexture.getTextureUnit();
680
+ cellBO.getProgram().setUniformi('volumeTexture', texUnit);
681
+ cellBO.getProgram().setUniformf('width', model.renderable.getWidth());
682
+
683
+ (_cellBO$getProgram = cellBO.getProgram()).setUniform4f.apply(_cellBO$getProgram, ['backgroundColor'].concat(_toConsumableArray(model.renderable.getBackgroundColor())));
684
+
685
+ if (cellBO.getProgram().isUniformUsed('centerlineDirection')) {
686
+ var uniformDirection = model.renderable.getUniformDirection();
687
+ cellBO.getProgram().setUniform3fArray('centerlineDirection', uniformDirection);
688
+ } // Model coordinates to image space
689
+ // getWorldToIndex is badly named and is in fact modelToIndex
690
+ // MCIC -> Model coordinates to index coordinates
691
+ // MCTC -> Model coordinates to texture coordinates
692
+
693
+
694
+ var image = model.currentImageDataInput;
695
+ var MCICMatrix = image.getWorldToIndex();
696
+ var ICTCMatrix = mat4.fromScaling(new Float32Array(16), vec3.inverse([], image.getDimensions()));
697
+ var MCTCMatrix = mat4.mul(ICTCMatrix, ICTCMatrix, MCICMatrix);
698
+ cellBO.getProgram().setUniformMatrix('MCTCMatrix', MCTCMatrix);
699
+
700
+ if (model.haveSeenDepthRequest) {
701
+ cellBO.getProgram().setUniformi('depthRequest', model.renderDepth ? 1 : 0);
702
+ }
703
+
704
+ if (model.renderable.getNumberOfClippingPlanes()) {
705
+ // add all the clipping planes
706
+ var numClipPlanes = model.renderable.getNumberOfClippingPlanes();
707
+
708
+ if (numClipPlanes > 6) {
709
+ macro.vtkErrorMacro('OpenGL has a limit of 6 clipping planes');
710
+ numClipPlanes = 6;
711
+ }
712
+
713
+ var shiftScaleEnabled = cellBO.getCABO().getCoordShiftAndScaleEnabled();
714
+ var inverseShiftScaleMatrix = shiftScaleEnabled ? cellBO.getCABO().getInverseShiftAndScaleMatrix() : null;
715
+ var mat = inverseShiftScaleMatrix ? mat4.copy(model.imagematinv, actor.getMatrix()) : actor.getMatrix();
716
+
717
+ if (inverseShiftScaleMatrix) {
718
+ mat4.transpose(mat, mat);
719
+ mat4.multiply(mat, mat, inverseShiftScaleMatrix);
720
+ mat4.transpose(mat, mat);
721
+ } // transform crop plane normal with transpose(inverse(worldToIndex))
722
+
723
+
724
+ mat4.transpose(model.imagemat, model.currentImageDataInput.getIndexToWorld());
725
+ mat4.multiply(model.imagematinv, mat, model.imagemat);
726
+ var planeEquations = [];
727
+
728
+ for (var i = 0; i < numClipPlanes; i++) {
729
+ var planeEquation = [];
730
+ model.renderable.getClippingPlaneInDataCoords(model.imagematinv, i, planeEquation);
731
+
732
+ for (var j = 0; j < 4; j++) {
733
+ planeEquations.push(planeEquation[j]);
734
+ }
735
+ }
736
+
737
+ cellBO.getProgram().setUniformi('numClipPlanes', numClipPlanes);
738
+ cellBO.getProgram().setUniform4fv('clipPlanes', planeEquations);
739
+ } // handle coincident
740
+
741
+
742
+ if (cellBO.getProgram().isUniformUsed('coffset')) {
743
+ var cp = publicAPI.getCoincidentParameters(ren, actor);
744
+ cellBO.getProgram().setUniformf('coffset', cp.offset); // cfactor isn't always used when coffset is.
745
+
746
+ if (cellBO.getProgram().isUniformUsed('cfactor')) {
747
+ cellBO.getProgram().setUniformf('cfactor', cp.factor);
748
+ }
749
+ }
750
+ };
751
+
752
+ publicAPI.setCameraShaderParameters = function (cellBO, ren, actor) {
753
+ var MCWCMatrix = model.openGLImageSlice.getKeyMatrices().mcwc;
754
+ var WCPCMatrix = model.openGLCamera.getKeyMatrices(ren).wcpc;
755
+ mat4.multiply(model.imagemat, WCPCMatrix, MCWCMatrix);
756
+
757
+ if (cellBO.getCABO().getCoordShiftAndScaleEnabled()) {
758
+ var inverseShiftScaleMat = cellBO.getCABO().getInverseShiftAndScaleMatrix();
759
+ mat4.multiply(model.imagemat, model.imagemat, inverseShiftScaleMat);
760
+ }
761
+
762
+ cellBO.getProgram().setUniformMatrix('MCPCMatrix', model.imagemat);
763
+ };
764
+
765
+ publicAPI.setPropertyShaderParameters = function (cellBO, ren, actor) {
766
+ var program = cellBO.getProgram();
767
+ var ppty = actor.getProperty();
768
+ var opacity = ppty.getOpacity();
769
+ program.setUniformf('opacity', opacity); // Component mix
770
+ // Independent components: Mixed according to component weights
771
+ // Dependent components: Mixed using the following logic:
772
+ // - 2 comps => LA
773
+ // - 3 comps => RGB + opacity from pwf
774
+ // - 4 comps => RGBA
775
+
776
+ var numComp = model.volumeTexture.getComponents();
777
+ var iComps = ppty.getIndependentComponents();
778
+
779
+ if (iComps) {
780
+ for (var i = 0; i < numComp; ++i) {
781
+ program.setUniformf("mix".concat(i), ppty.getComponentWeight(i));
782
+ }
783
+ } // Color opacity map
784
+
785
+
786
+ var volInfo = model.volumeTexture.getVolumeInfo(); // three levels of shift scale combined into one
787
+ // for performance in the fragment shader
788
+
789
+ for (var _i6 = 0; _i6 < numComp; _i6++) {
790
+ var cw = ppty.getColorWindow();
791
+ var cl = ppty.getColorLevel();
792
+ var target = iComps ? _i6 : 0;
793
+ var cfun = ppty.getRGBTransferFunction(target);
794
+
795
+ if (cfun && ppty.getUseLookupTableScalarRange()) {
796
+ var cRange = cfun.getRange();
797
+ cw = cRange[1] - cRange[0];
798
+ cl = 0.5 * (cRange[1] + cRange[0]);
799
+ }
800
+
801
+ var scale = volInfo.scale[_i6] / cw;
802
+ var shift = (volInfo.offset[_i6] - cl) / cw + 0.5;
803
+ program.setUniformf("cshift".concat(_i6), shift);
804
+ program.setUniformf("cscale".concat(_i6), scale);
805
+ }
806
+
807
+ var texColorUnit = model.colorTexture.getTextureUnit(); // TODO
808
+
809
+ program.setUniformi('colorTexture1', texColorUnit); // pwf shift/scale
810
+
811
+ for (var _i7 = 0; _i7 < numComp; _i7++) {
812
+ var pwfScale = 1.0;
813
+ var pwfShift = 0.0;
814
+
815
+ var _target = iComps ? _i7 : 0;
816
+
817
+ var pwfun = ppty.getPiecewiseFunction(_target);
818
+
819
+ if (pwfun) {
820
+ var pwfRange = pwfun.getRange();
821
+ var length = pwfRange[1] - pwfRange[0];
822
+ var mid = 0.5 * (pwfRange[0] + pwfRange[1]);
823
+ pwfScale = volInfo.scale[_i7] / length;
824
+ pwfShift = (volInfo.offset[_i7] - mid) / length + 0.5;
825
+ }
826
+
827
+ program.setUniformf("pwfshift".concat(_i7), pwfShift);
828
+ program.setUniformf("pwfscale".concat(_i7), pwfScale);
829
+ }
830
+
831
+ var texOpacityUnit = model.pwfTexture.getTextureUnit(); // TODO
832
+
833
+ program.setUniformi('pwfTexture1', texOpacityUnit);
834
+ };
835
+
836
+ publicAPI.updateShaders = function (cellBO, ren, actor) {
837
+ // has something changed that would require us to recreate the shader?
838
+ if (publicAPI.getNeedToRebuildShaders(cellBO, ren, actor)) {
839
+ var shaders = {
840
+ Vertex: null,
841
+ Fragment: null,
842
+ Geometry: null
843
+ };
844
+ publicAPI.buildShaders(shaders, ren, actor); // compile and bind the program if needed
845
+
846
+ var newShader = model._openGLRenderWindow.getShaderCache().readyShaderProgramArray(shaders.Vertex, shaders.Fragment, shaders.Geometry); // if the shader changed reinitialize the VAO
847
+
848
+
849
+ if (newShader !== cellBO.getProgram()) {
850
+ cellBO.setProgram(newShader); // reset the VAO as the shader has changed
851
+
852
+ cellBO.getVAO().releaseGraphicsResources();
853
+ }
854
+
855
+ cellBO.getShaderSourceTime().modified();
856
+ } else {
857
+ model._openGLRenderWindow.getShaderCache().readyShaderProgram(cellBO.getProgram());
858
+ }
859
+
860
+ cellBO.getVAO().bind();
861
+ publicAPI.setMapperShaderParameters(cellBO, ren, actor);
862
+ publicAPI.setCameraShaderParameters(cellBO, ren, actor);
863
+ publicAPI.setPropertyShaderParameters(cellBO, ren, actor);
864
+ };
865
+ } // ----------------------------------------------------------------------------
866
+ // Object factory
867
+ // ----------------------------------------------------------------------------
868
+
869
+
870
+ var DEFAULT_VALUES = {
871
+ currentRenderPass: null,
872
+ volumeTexture: null,
873
+ volumeTextureTime: 0,
874
+ colorTexture: null,
875
+ colorTextureString: null,
876
+ pwfTexture: null,
877
+ pwfTextureString: null,
878
+ tris: null,
879
+ lastHaveSeenDepthRequest: false,
880
+ haveSeenDepthRequest: false,
881
+ lastTextureComponents: 0,
882
+ lastIndependentComponents: 0,
883
+ imagemat: null,
884
+ imagematinv: null
885
+ }; // ----------------------------------------------------------------------------
886
+
887
+ function extend(publicAPI, model) {
888
+ var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
889
+ Object.assign(model, DEFAULT_VALUES, initialValues); // Inheritance
890
+
891
+ vtkViewNode.extend(publicAPI, model, initialValues);
892
+ vtkReplacementShaderMapper.implementReplaceShaderCoincidentOffset(publicAPI, model, initialValues); // Two inputs: one for the ImageData/Texture and one for the PolyData (centerline)
893
+
894
+ macro.algo(publicAPI, model, 2, 0);
895
+ model.tris = vtkHelper.newInstance();
896
+ model.volumeTexture = vtkOpenGLTexture.newInstance();
897
+ model.colorTexture = vtkOpenGLTexture.newInstance();
898
+ model.pwfTexture = vtkOpenGLTexture.newInstance();
899
+ model.imagemat = mat4.identity(new Float64Array(16));
900
+ model.imagematinv = mat4.identity(new Float64Array(16));
901
+ model.VBOBuildTime = {};
902
+ macro.obj(model.VBOBuildTime, {
903
+ mtime: 0
904
+ }); // Object methods
905
+
906
+ vtkOpenGLImageCPRMapper(publicAPI, model);
907
+ } // ----------------------------------------------------------------------------
908
+
909
+ var newInstance = macro.newInstance(extend, 'vtkOpenGLImageCPRMapper');
910
+ var STATIC = {}; // ----------------------------------------------------------------------------
911
+
912
+ var index = _objectSpread({
913
+ newInstance: newInstance,
914
+ extend: extend
915
+ }, STATIC); // Register ourself to OpenGL backend if imported
916
+
917
+ registerOverride('vtkImageCPRMapper', newInstance);
918
+
919
+ export { STATIC, index as default, extend, newInstance };