@niivue/niivue 0.24.2 → 0.24.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/niivue.es.js CHANGED
@@ -787,6 +787,14 @@ float frac2ndc(vec3 frac) {
787
787
  }
788
788
  void main() {
789
789
  fColor = vec4(0.0,0.0,0.0,0.0);
790
+ vec4 clipPlaneColorX = clipPlaneColor;
791
+ //if (clipPlaneColor.a < 0.0)
792
+ // clipPlaneColorX.a = - 1.0;
793
+ bool isColorPlaneInVolume = false;
794
+ if (clipPlaneColorX.a < 0.0) {
795
+ isColorPlaneInVolume = true;
796
+ clipPlaneColorX.a = 0.0;
797
+ }
790
798
  //fColor = vec4(vColor.rgb, 1.0); return;
791
799
  vec3 start = vColor;
792
800
  gl_FragDepth = 0.0;
@@ -818,7 +826,7 @@ void main() {
818
826
  }
819
827
  if ((samplePos.a >= len) && ((overlays < 1.0) || (backgroundMasksOverlays > 0))) {
820
828
  if (isClip)
821
- fColor += clipPlaneColor;
829
+ fColor += clipPlaneColorX;
822
830
  return;
823
831
  }
824
832
  fColor = vec4(1.0, 1.0, 1.0, 1.0);
@@ -850,8 +858,10 @@ void main() {
850
858
  gl_FragDepth = frac2ndc(firstHit.xyz);
851
859
  colAcc.a = (colAcc.a / earlyTermination) * backOpacity;
852
860
  fColor = colAcc;
853
- if (isClip) //CR
854
- fColor.rgb = mix(fColor.rgb, clipPlaneColor.rgb, clipPlaneColor.a * 0.15);
861
+ //if (isClip) //CR
862
+ if ((isColorPlaneInVolume) && (clipPos.a != samplePos.a) && (abs(firstHit.a - clipPos.a) < deltaDir.a))
863
+ fColor.rgb = mix(fColor.rgb, clipPlaneColorX.rgb, abs(clipPlaneColor.a));
864
+ //fColor.rgb = mix(fColor.rgb, clipPlaneColorX.rgb, clipPlaneColorX.a * 0.65);
855
865
  if (overlays < 1.0) return;
856
866
  //overlay pass
857
867
  len = lenNoClip;
@@ -866,7 +876,7 @@ void main() {
866
876
  }
867
877
  if (samplePos.a >= len) {
868
878
  if (isClip && (fColor.a == 0.0))
869
- fColor += clipPlaneColor;
879
+ fColor += clipPlaneColorX;
870
880
  return;
871
881
  }
872
882
  samplePos -= deltaDirFast;
@@ -894,7 +904,7 @@ void main() {
894
904
  }
895
905
  if (samplePos.a >= len) {
896
906
  if (isClip && (fColor.a == 0.0))
897
- fColor += clipPlaneColor;
907
+ fColor += clipPlaneColorX;
898
908
  return;
899
909
  }
900
910
  //if (overFirstHit.a < len)
@@ -1290,15 +1300,13 @@ var fragGrowCutShader = `#version 300 es
1290
1300
  layout(location = 0) out int label;
1291
1301
  layout(location = 1) out int strength;
1292
1302
  in vec2 TexCoord;
1293
- //out vec4 FragColor;
1303
+ uniform int finalPass;
1294
1304
  uniform float coordZ;
1295
1305
  uniform lowp sampler3D in3D;
1296
1306
  uniform highp isampler3D inputTexture0; // background
1297
1307
  uniform highp isampler3D inputTexture1; // label
1298
1308
  uniform highp isampler3D inputTexture2; // strength
1299
1309
  void main(void) {
1300
- //int MAX_STRENGTH = int(255);
1301
- int MAX_STRENGTH = int(10000);
1302
1310
  vec3 interpolatedTextureCoordinate = vec3(TexCoord.xy, coordZ);
1303
1311
  ivec3 size = textureSize(inputTexture0, 0);
1304
1312
  ivec3 texelIndex = ivec3(floor(interpolatedTextureCoordinate * vec3(size)));
@@ -1322,6 +1330,29 @@ void main(void) {
1322
1330
  }
1323
1331
  }
1324
1332
  }
1333
+ if (finalPass < 1)
1334
+ return;
1335
+ int ok = 1;
1336
+ ivec4 labelCount = ivec4(0,0,0,0);
1337
+ for (int k = -1; k <= 1; k++)
1338
+ for (int j = -1; j <= 1; j++)
1339
+ for (int i = -1; i <= 1; i++) {
1340
+ ivec3 neighborIndex = texelIndex + ivec3(i,j,k);
1341
+ int ilabel = texelFetch(inputTexture1, neighborIndex, 0).r;
1342
+ if ((ilabel < 0) || (ilabel > 3))
1343
+ ok = 0;
1344
+ else
1345
+ labelCount[ilabel]++;
1346
+ }
1347
+ if (ok != 1) {
1348
+ return;
1349
+ }
1350
+ int maxIdx = 0;
1351
+ for (int i = 1; i < 4; i++) {
1352
+ if (labelCount[i] > labelCount[maxIdx])
1353
+ maxIdx = i;
1354
+ }
1355
+ label = maxIdx;
1325
1356
  }`;
1326
1357
  var vertSurfaceShader = `#version 300 es
1327
1358
  layout(location=0) in vec3 pos;
@@ -1672,6 +1703,18 @@ function __extends(d, b) {
1672
1703
  }
1673
1704
  d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
1674
1705
  }
1706
+ var __assign = function() {
1707
+ __assign = Object.assign || function __assign2(t) {
1708
+ for (var s, i2 = 1, n = arguments.length; i2 < n; i2++) {
1709
+ s = arguments[i2];
1710
+ for (var p in s)
1711
+ if (Object.prototype.hasOwnProperty.call(s, p))
1712
+ t[p] = s[p];
1713
+ }
1714
+ return t;
1715
+ };
1716
+ return __assign.apply(this, arguments);
1717
+ };
1675
1718
  function __values(o) {
1676
1719
  var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i2 = 0;
1677
1720
  if (m)
@@ -1916,6 +1959,22 @@ function reportUnhandledError(err2) {
1916
1959
  }
1917
1960
  function noop() {
1918
1961
  }
1962
+ var COMPLETE_NOTIFICATION = function() {
1963
+ return createNotification("C", void 0, void 0);
1964
+ }();
1965
+ function errorNotification(error) {
1966
+ return createNotification("E", void 0, error);
1967
+ }
1968
+ function nextNotification(value2) {
1969
+ return createNotification("N", value2, void 0);
1970
+ }
1971
+ function createNotification(kind, value2, error) {
1972
+ return {
1973
+ kind,
1974
+ value: value2,
1975
+ error
1976
+ };
1977
+ }
1919
1978
  var context = null;
1920
1979
  function errorContext(cb) {
1921
1980
  if (config.useDeprecatedSynchronousErrorHandling) {
@@ -1954,24 +2013,24 @@ var Subscriber = function(_super) {
1954
2013
  return new SafeSubscriber(next, error, complete);
1955
2014
  };
1956
2015
  Subscriber2.prototype.next = function(value2) {
1957
- if (this.isStopped)
1958
- ;
1959
- else {
2016
+ if (this.isStopped) {
2017
+ handleStoppedNotification(nextNotification(value2), this);
2018
+ } else {
1960
2019
  this._next(value2);
1961
2020
  }
1962
2021
  };
1963
2022
  Subscriber2.prototype.error = function(err2) {
1964
- if (this.isStopped)
1965
- ;
1966
- else {
2023
+ if (this.isStopped) {
2024
+ handleStoppedNotification(errorNotification(err2), this);
2025
+ } else {
1967
2026
  this.isStopped = true;
1968
2027
  this._error(err2);
1969
2028
  }
1970
2029
  };
1971
2030
  Subscriber2.prototype.complete = function() {
1972
- if (this.isStopped)
1973
- ;
1974
- else {
2031
+ if (this.isStopped) {
2032
+ handleStoppedNotification(COMPLETE_NOTIFICATION, this);
2033
+ } else {
1975
2034
  this.isStopped = true;
1976
2035
  this._complete();
1977
2036
  }
@@ -2084,6 +2143,12 @@ function handleUnhandledError(error) {
2084
2143
  function defaultErrorHandler(err2) {
2085
2144
  throw err2;
2086
2145
  }
2146
+ function handleStoppedNotification(notification, subscriber) {
2147
+ var onStoppedNotification = config.onStoppedNotification;
2148
+ onStoppedNotification && timeoutProvider.setTimeout(function() {
2149
+ return onStoppedNotification(notification, subscriber);
2150
+ });
2151
+ }
2087
2152
  var EMPTY_OBSERVER = {
2088
2153
  closed: true,
2089
2154
  next: noop,
@@ -2361,6 +2426,289 @@ var AnonymousSubject = function(_super) {
2361
2426
  };
2362
2427
  return AnonymousSubject2;
2363
2428
  }(Subject);
2429
+ var dateTimestampProvider = {
2430
+ now: function() {
2431
+ return (dateTimestampProvider.delegate || Date).now();
2432
+ },
2433
+ delegate: void 0
2434
+ };
2435
+ var ReplaySubject = function(_super) {
2436
+ __extends(ReplaySubject2, _super);
2437
+ function ReplaySubject2(_bufferSize, _windowTime, _timestampProvider) {
2438
+ if (_bufferSize === void 0) {
2439
+ _bufferSize = Infinity;
2440
+ }
2441
+ if (_windowTime === void 0) {
2442
+ _windowTime = Infinity;
2443
+ }
2444
+ if (_timestampProvider === void 0) {
2445
+ _timestampProvider = dateTimestampProvider;
2446
+ }
2447
+ var _this = _super.call(this) || this;
2448
+ _this._bufferSize = _bufferSize;
2449
+ _this._windowTime = _windowTime;
2450
+ _this._timestampProvider = _timestampProvider;
2451
+ _this._buffer = [];
2452
+ _this._infiniteTimeWindow = true;
2453
+ _this._infiniteTimeWindow = _windowTime === Infinity;
2454
+ _this._bufferSize = Math.max(1, _bufferSize);
2455
+ _this._windowTime = Math.max(1, _windowTime);
2456
+ return _this;
2457
+ }
2458
+ ReplaySubject2.prototype.next = function(value2) {
2459
+ var _a2 = this, isStopped = _a2.isStopped, _buffer = _a2._buffer, _infiniteTimeWindow = _a2._infiniteTimeWindow, _timestampProvider = _a2._timestampProvider, _windowTime = _a2._windowTime;
2460
+ if (!isStopped) {
2461
+ _buffer.push(value2);
2462
+ !_infiniteTimeWindow && _buffer.push(_timestampProvider.now() + _windowTime);
2463
+ }
2464
+ this._trimBuffer();
2465
+ _super.prototype.next.call(this, value2);
2466
+ };
2467
+ ReplaySubject2.prototype._subscribe = function(subscriber) {
2468
+ this._throwIfClosed();
2469
+ this._trimBuffer();
2470
+ var subscription = this._innerSubscribe(subscriber);
2471
+ var _a2 = this, _infiniteTimeWindow = _a2._infiniteTimeWindow, _buffer = _a2._buffer;
2472
+ var copy2 = _buffer.slice();
2473
+ for (var i2 = 0; i2 < copy2.length && !subscriber.closed; i2 += _infiniteTimeWindow ? 1 : 2) {
2474
+ subscriber.next(copy2[i2]);
2475
+ }
2476
+ this._checkFinalizedStatuses(subscriber);
2477
+ return subscription;
2478
+ };
2479
+ ReplaySubject2.prototype._trimBuffer = function() {
2480
+ var _a2 = this, _bufferSize = _a2._bufferSize, _timestampProvider = _a2._timestampProvider, _buffer = _a2._buffer, _infiniteTimeWindow = _a2._infiniteTimeWindow;
2481
+ var adjustedBufferSize = (_infiniteTimeWindow ? 1 : 2) * _bufferSize;
2482
+ _bufferSize < Infinity && adjustedBufferSize < _buffer.length && _buffer.splice(0, _buffer.length - adjustedBufferSize);
2483
+ if (!_infiniteTimeWindow) {
2484
+ var now = _timestampProvider.now();
2485
+ var last = 0;
2486
+ for (var i2 = 1; i2 < _buffer.length && _buffer[i2] <= now; i2 += 2) {
2487
+ last = i2;
2488
+ }
2489
+ last && _buffer.splice(0, last + 1);
2490
+ }
2491
+ };
2492
+ return ReplaySubject2;
2493
+ }(Subject);
2494
+ var Action = function(_super) {
2495
+ __extends(Action2, _super);
2496
+ function Action2(scheduler, work) {
2497
+ return _super.call(this) || this;
2498
+ }
2499
+ Action2.prototype.schedule = function(state, delay) {
2500
+ return this;
2501
+ };
2502
+ return Action2;
2503
+ }(Subscription);
2504
+ var intervalProvider = {
2505
+ setInterval: function(handler, timeout) {
2506
+ var args = [];
2507
+ for (var _i = 2; _i < arguments.length; _i++) {
2508
+ args[_i - 2] = arguments[_i];
2509
+ }
2510
+ var delegate = intervalProvider.delegate;
2511
+ if (delegate === null || delegate === void 0 ? void 0 : delegate.setInterval) {
2512
+ return delegate.setInterval.apply(delegate, __spreadArray([handler, timeout], __read(args)));
2513
+ }
2514
+ return setInterval.apply(void 0, __spreadArray([handler, timeout], __read(args)));
2515
+ },
2516
+ clearInterval: function(handle) {
2517
+ var delegate = intervalProvider.delegate;
2518
+ return ((delegate === null || delegate === void 0 ? void 0 : delegate.clearInterval) || clearInterval)(handle);
2519
+ },
2520
+ delegate: void 0
2521
+ };
2522
+ var AsyncAction = function(_super) {
2523
+ __extends(AsyncAction2, _super);
2524
+ function AsyncAction2(scheduler, work) {
2525
+ var _this = _super.call(this, scheduler, work) || this;
2526
+ _this.scheduler = scheduler;
2527
+ _this.work = work;
2528
+ _this.pending = false;
2529
+ return _this;
2530
+ }
2531
+ AsyncAction2.prototype.schedule = function(state, delay) {
2532
+ if (delay === void 0) {
2533
+ delay = 0;
2534
+ }
2535
+ if (this.closed) {
2536
+ return this;
2537
+ }
2538
+ this.state = state;
2539
+ var id = this.id;
2540
+ var scheduler = this.scheduler;
2541
+ if (id != null) {
2542
+ this.id = this.recycleAsyncId(scheduler, id, delay);
2543
+ }
2544
+ this.pending = true;
2545
+ this.delay = delay;
2546
+ this.id = this.id || this.requestAsyncId(scheduler, this.id, delay);
2547
+ return this;
2548
+ };
2549
+ AsyncAction2.prototype.requestAsyncId = function(scheduler, _id, delay) {
2550
+ if (delay === void 0) {
2551
+ delay = 0;
2552
+ }
2553
+ return intervalProvider.setInterval(scheduler.flush.bind(scheduler, this), delay);
2554
+ };
2555
+ AsyncAction2.prototype.recycleAsyncId = function(_scheduler, id, delay) {
2556
+ if (delay === void 0) {
2557
+ delay = 0;
2558
+ }
2559
+ if (delay != null && this.delay === delay && this.pending === false) {
2560
+ return id;
2561
+ }
2562
+ intervalProvider.clearInterval(id);
2563
+ return void 0;
2564
+ };
2565
+ AsyncAction2.prototype.execute = function(state, delay) {
2566
+ if (this.closed) {
2567
+ return new Error("executing a cancelled action");
2568
+ }
2569
+ this.pending = false;
2570
+ var error = this._execute(state, delay);
2571
+ if (error) {
2572
+ return error;
2573
+ } else if (this.pending === false && this.id != null) {
2574
+ this.id = this.recycleAsyncId(this.scheduler, this.id, null);
2575
+ }
2576
+ };
2577
+ AsyncAction2.prototype._execute = function(state, _delay) {
2578
+ var errored = false;
2579
+ var errorValue;
2580
+ try {
2581
+ this.work(state);
2582
+ } catch (e) {
2583
+ errored = true;
2584
+ errorValue = e ? e : new Error("Scheduled action threw falsy error");
2585
+ }
2586
+ if (errored) {
2587
+ this.unsubscribe();
2588
+ return errorValue;
2589
+ }
2590
+ };
2591
+ AsyncAction2.prototype.unsubscribe = function() {
2592
+ if (!this.closed) {
2593
+ var _a2 = this, id = _a2.id, scheduler = _a2.scheduler;
2594
+ var actions = scheduler.actions;
2595
+ this.work = this.state = this.scheduler = null;
2596
+ this.pending = false;
2597
+ arrRemove(actions, this);
2598
+ if (id != null) {
2599
+ this.id = this.recycleAsyncId(scheduler, id, null);
2600
+ }
2601
+ this.delay = null;
2602
+ _super.prototype.unsubscribe.call(this);
2603
+ }
2604
+ };
2605
+ return AsyncAction2;
2606
+ }(Action);
2607
+ var Scheduler = function() {
2608
+ function Scheduler2(schedulerActionCtor, now) {
2609
+ if (now === void 0) {
2610
+ now = Scheduler2.now;
2611
+ }
2612
+ this.schedulerActionCtor = schedulerActionCtor;
2613
+ this.now = now;
2614
+ }
2615
+ Scheduler2.prototype.schedule = function(work, delay, state) {
2616
+ if (delay === void 0) {
2617
+ delay = 0;
2618
+ }
2619
+ return new this.schedulerActionCtor(this, work).schedule(state, delay);
2620
+ };
2621
+ Scheduler2.now = dateTimestampProvider.now;
2622
+ return Scheduler2;
2623
+ }();
2624
+ var AsyncScheduler = function(_super) {
2625
+ __extends(AsyncScheduler2, _super);
2626
+ function AsyncScheduler2(SchedulerAction, now) {
2627
+ if (now === void 0) {
2628
+ now = Scheduler.now;
2629
+ }
2630
+ var _this = _super.call(this, SchedulerAction, now) || this;
2631
+ _this.actions = [];
2632
+ _this._active = false;
2633
+ _this._scheduled = void 0;
2634
+ return _this;
2635
+ }
2636
+ AsyncScheduler2.prototype.flush = function(action) {
2637
+ var actions = this.actions;
2638
+ if (this._active) {
2639
+ actions.push(action);
2640
+ return;
2641
+ }
2642
+ var error;
2643
+ this._active = true;
2644
+ do {
2645
+ if (error = action.execute(action.state, action.delay)) {
2646
+ break;
2647
+ }
2648
+ } while (action = actions.shift());
2649
+ this._active = false;
2650
+ if (error) {
2651
+ while (action = actions.shift()) {
2652
+ action.unsubscribe();
2653
+ }
2654
+ throw error;
2655
+ }
2656
+ };
2657
+ return AsyncScheduler2;
2658
+ }(Scheduler);
2659
+ var asyncScheduler = new AsyncScheduler(AsyncAction);
2660
+ var async = asyncScheduler;
2661
+ function isScheduler(value2) {
2662
+ return value2 && isFunction(value2.schedule);
2663
+ }
2664
+ function isValidDate(value2) {
2665
+ return value2 instanceof Date && !isNaN(value2);
2666
+ }
2667
+ function timer(dueTime, intervalOrScheduler, scheduler) {
2668
+ if (dueTime === void 0) {
2669
+ dueTime = 0;
2670
+ }
2671
+ if (scheduler === void 0) {
2672
+ scheduler = async;
2673
+ }
2674
+ var intervalDuration = -1;
2675
+ if (intervalOrScheduler != null) {
2676
+ if (isScheduler(intervalOrScheduler)) {
2677
+ scheduler = intervalOrScheduler;
2678
+ } else {
2679
+ intervalDuration = intervalOrScheduler;
2680
+ }
2681
+ }
2682
+ return new Observable(function(subscriber) {
2683
+ var due = isValidDate(dueTime) ? +dueTime - scheduler.now() : dueTime;
2684
+ if (due < 0) {
2685
+ due = 0;
2686
+ }
2687
+ var n = 0;
2688
+ return scheduler.schedule(function() {
2689
+ if (!subscriber.closed) {
2690
+ subscriber.next(n++);
2691
+ if (0 <= intervalDuration) {
2692
+ this.schedule(void 0, intervalDuration);
2693
+ } else {
2694
+ subscriber.complete();
2695
+ }
2696
+ }
2697
+ }, due);
2698
+ });
2699
+ }
2700
+ function interval(period, scheduler) {
2701
+ if (period === void 0) {
2702
+ period = 0;
2703
+ }
2704
+ if (scheduler === void 0) {
2705
+ scheduler = asyncScheduler;
2706
+ }
2707
+ if (period < 0) {
2708
+ period = 0;
2709
+ }
2710
+ return timer(period, period, scheduler);
2711
+ }
2364
2712
  var NiivueObject3D = function(id, vertexBuffer, mode, indexCount, indexBuffer = null, vao = null) {
2365
2713
  this.BLEND = 1;
2366
2714
  this.CULL_FACE = 2;
@@ -2785,12 +3133,12 @@ var utilities$1 = { exports: {} };
2785
3133
  return data.getFloat64(start, littleEndian);
2786
3134
  };
2787
3135
  nifti3.Utils.getLongAt = function(data, start, littleEndian) {
2788
- var ctr, array = [], value2 = 0;
3136
+ var ctr, array2 = [], value2 = 0;
2789
3137
  for (ctr = 0; ctr < 8; ctr += 1) {
2790
- array[ctr] = nifti3.Utils.getByteAt(data, start + ctr, littleEndian);
3138
+ array2[ctr] = nifti3.Utils.getByteAt(data, start + ctr, littleEndian);
2791
3139
  }
2792
- for (ctr = array.length - 1; ctr >= 0; ctr--) {
2793
- value2 = value2 * 256 + array[ctr];
3140
+ for (ctr = array2.length - 1; ctr >= 0; ctr--) {
3141
+ value2 = value2 * 256 + array2[ctr];
2794
3142
  }
2795
3143
  return value2;
2796
3144
  };
@@ -7674,24 +8022,24 @@ var utilities = { exports: {} };
7674
8022
  }
7675
8023
  return tmp.buffer;
7676
8024
  };
7677
- daikon2.Utils.fillBuffer = function(array, buffer2, offset, numBytes) {
8025
+ daikon2.Utils.fillBuffer = function(array2, buffer2, offset, numBytes) {
7678
8026
  var ctr;
7679
8027
  if (numBytes === 1) {
7680
- for (ctr = 0; ctr < array.length; ctr += 1) {
7681
- buffer2.setUint8(offset + ctr, array[ctr]);
8028
+ for (ctr = 0; ctr < array2.length; ctr += 1) {
8029
+ buffer2.setUint8(offset + ctr, array2[ctr]);
7682
8030
  }
7683
8031
  } else if (numBytes === 2) {
7684
- for (ctr = 0; ctr < array.length; ctr += 1) {
7685
- buffer2.setUint16(offset + ctr * 2, array[ctr], true);
8032
+ for (ctr = 0; ctr < array2.length; ctr += 1) {
8033
+ buffer2.setUint16(offset + ctr * 2, array2[ctr], true);
7686
8034
  }
7687
8035
  }
7688
8036
  };
7689
- daikon2.Utils.fillBufferRGB = function(array, buffer2, offset) {
7690
- var r, g, b, ctr, numElements = parseInt(array.length / 3);
8037
+ daikon2.Utils.fillBufferRGB = function(array2, buffer2, offset) {
8038
+ var r, g, b, ctr, numElements = parseInt(array2.length / 3);
7691
8039
  for (ctr = 0; ctr < numElements; ctr += 1) {
7692
- r = array[ctr * 3];
7693
- g = array[ctr * 3 + 1];
7694
- b = array[ctr * 3 + 2];
8040
+ r = array2[ctr * 3];
8041
+ g = array2[ctr * 3 + 1];
8042
+ b = array2[ctr * 3 + 2];
7695
8043
  buffer2.setUint8(offset + ctr, parseInt((r + b + g) / 3), true);
7696
8044
  }
7697
8045
  };
@@ -13766,9 +14114,9 @@ var jpegBaseline = { exports: {} };
13766
14114
  }
13767
14115
  function readDataBlock() {
13768
14116
  var length2 = readUint16();
13769
- var array = data.subarray(offset, offset + length2 - 2);
13770
- offset += array.length;
13771
- return array;
14117
+ var array2 = data.subarray(offset, offset + length2 - 2);
14118
+ offset += array2.length;
14119
+ return array2;
13772
14120
  }
13773
14121
  function prepareComponents(frame2) {
13774
14122
  var mcusPerLine = Math.ceil(frame2.samplesPerLine / 8 / frame2.maxH);
@@ -18476,10 +18824,10 @@ var require$$1 = /* @__PURE__ */ getAugmentedNamespace(__viteBrowserExternal$1);
18476
18824
  return u8array;
18477
18825
  }
18478
18826
  Module["intArrayFromString"] = intArrayFromString;
18479
- function intArrayToString(array) {
18827
+ function intArrayToString(array2) {
18480
18828
  var ret = [];
18481
- for (var i2 = 0; i2 < array.length; i2++) {
18482
- var chr = array[i2];
18829
+ for (var i2 = 0; i2 < array2.length; i2++) {
18830
+ var chr = array2[i2];
18483
18831
  if (chr > 255) {
18484
18832
  chr &= 255;
18485
18833
  }
@@ -18489,18 +18837,18 @@ var require$$1 = /* @__PURE__ */ getAugmentedNamespace(__viteBrowserExternal$1);
18489
18837
  }
18490
18838
  Module["intArrayToString"] = intArrayToString;
18491
18839
  function writeStringToMemory(string, buffer2, dontAddNull) {
18492
- var array = intArrayFromString(string, dontAddNull);
18840
+ var array2 = intArrayFromString(string, dontAddNull);
18493
18841
  var i2 = 0;
18494
- while (i2 < array.length) {
18495
- var chr = array[i2];
18842
+ while (i2 < array2.length) {
18843
+ var chr = array2[i2];
18496
18844
  HEAP8[buffer2 + i2 >> 0] = chr;
18497
18845
  i2 = i2 + 1;
18498
18846
  }
18499
18847
  }
18500
18848
  Module["writeStringToMemory"] = writeStringToMemory;
18501
- function writeArrayToMemory(array, buffer2) {
18502
- for (var i2 = 0; i2 < array.length; i2++) {
18503
- HEAP8[buffer2++ >> 0] = array[i2];
18849
+ function writeArrayToMemory(array2, buffer2) {
18850
+ for (var i2 = 0; i2 < array2.length; i2++) {
18851
+ HEAP8[buffer2++ >> 0] = array2[i2];
18504
18852
  }
18505
18853
  }
18506
18854
  Module["writeArrayToMemory"] = writeArrayToMemory;
@@ -18674,9 +19022,9 @@ var require$$1 = /* @__PURE__ */ getAugmentedNamespace(__viteBrowserExternal$1);
18674
19022
  function __isLeapYear(year) {
18675
19023
  return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
18676
19024
  }
18677
- function __arraySum(array, index) {
19025
+ function __arraySum(array2, index) {
18678
19026
  var sum = 0;
18679
- for (var i2 = 0; i2 <= index; sum += array[i2++])
19027
+ for (var i2 = 0; i2 <= index; sum += array2[i2++])
18680
19028
  ;
18681
19029
  return sum;
18682
19030
  }
@@ -103140,7 +103488,7 @@ function NVImage(dataBuffer, name = "", colorMap = "gray", opacity = 1, pairedIm
103140
103488
  let nVol4D = imgRaw.byteLength / this.nVox3D / (this.hdr.numBitsPerVoxel / 8);
103141
103489
  if (nVol4D !== this.nFrame4D)
103142
103490
  console.log("This header does not match voxel data", this.hdr, imgRaw.byteLength);
103143
- if (this.hdr.intent_code === 1007 && this.nFrame4D === 3 && this.hdr.datatypeCode === this.DT_FLOAT) {
103491
+ if ((this.hdr.intent_code === 1007 || this.hdr.intent_code === 2003) && this.nFrame4D === 3 && this.hdr.datatypeCode === this.DT_FLOAT) {
103144
103492
  let tmp = new Float32Array(imgRaw);
103145
103493
  let f32 = tmp.slice();
103146
103494
  this.hdr.datatypeCode = this.DT_RGB;
@@ -103768,11 +104116,12 @@ NVImage.prototype.readMGH = function(buffer2) {
103768
104116
  let hdr = this.hdr;
103769
104117
  hdr.dims = [3, 1, 1, 1, 0, 0, 0, 0];
103770
104118
  hdr.pixDims = [1, 1, 1, 1, 1, 0, 0, 0];
103771
- var reader = new DataView(buffer2);
103772
104119
  var raw = buffer2;
104120
+ var reader = new DataView(raw);
103773
104121
  if (reader.getUint8(0) === 31 && reader.getUint8(1) === 139) {
103774
- var raw = decompressSync(new Uint8Array(buffer2));
103775
- reader = new DataView(raw.buffer);
104122
+ let raw8 = decompressSync(new Uint8Array(buffer2));
104123
+ raw = raw8.buffer;
104124
+ reader = new DataView(raw);
103776
104125
  }
103777
104126
  let version = reader.getInt32(0, false);
103778
104127
  let width = reader.getInt32(4, false);
@@ -106753,19 +107102,30 @@ NVMesh.readPLY = function(buffer2) {
106753
107102
  }
106754
107103
  let indices2 = new Int32Array(nface * 3);
106755
107104
  let f = 0;
106756
- let isTriangular2 = true;
106757
107105
  for (var i2 = 0; i2 < nface; i2++) {
106758
107106
  line = readStr();
106759
107107
  let items = line.split(/\s/);
106760
- if (parseInt(items[0]) > 3)
106761
- isTriangular2 = false;
106762
- indices2[f] = parseInt(items[1]);
106763
- indices2[f + 1] = parseInt(items[2]);
106764
- indices2[f + 2] = parseInt(items[3]);
106765
- f += 3;
106766
- }
106767
- if (!isTriangular2)
106768
- console.log("Only able to read PLY meshes limited to triangles.");
107108
+ let nTri = parseInt(items[0]) - 2;
107109
+ if (nTri < 1)
107110
+ break;
107111
+ if (f + nTri * 3 > indices2.length) {
107112
+ var c2 = new Int32Array(indices2.length + indices2.length);
107113
+ c2.set(indices2);
107114
+ indices2 = c2.slice();
107115
+ }
107116
+ let idx0 = parseInt(items[1]);
107117
+ let idx1 = parseInt(items[2]);
107118
+ for (let j2 = 0; j2 < nTri; j2++) {
107119
+ let idx2 = parseInt(items[3 + j2]);
107120
+ indices2[f + 0] = idx0;
107121
+ indices2[f + 1] = idx1;
107122
+ indices2[f + 2] = idx2;
107123
+ idx1 = idx2;
107124
+ f += 3;
107125
+ }
107126
+ }
107127
+ if (indices2.length !== f)
107128
+ indices2 = indices2.slice(0, f);
106769
107129
  return {
106770
107130
  positions: positions2,
106771
107131
  indices: indices2
@@ -106956,12 +107316,21 @@ NVMesh.readOBJ = function(buffer2) {
106956
107316
  }
106957
107317
  if (str[0] === "f") {
106958
107318
  let items = str.split(" ");
107319
+ let new_t = items.length - 3;
107320
+ if (new_t < 1)
107321
+ break;
106959
107322
  let tn = items[1].split("/");
106960
- t.push(parseInt(tn - 1));
107323
+ let t0 = parseInt(tn[0]) - 1;
106961
107324
  tn = items[2].split("/");
106962
- t.push(parseInt(tn - 1));
106963
- tn = items[3].split("/");
106964
- t.push(parseInt(tn - 1));
107325
+ let tprev = parseInt(tn[0]) - 1;
107326
+ for (let j = 0; j < new_t; j++) {
107327
+ tn = items[3 + j].split("/");
107328
+ let tcurr = parseInt(tn[0]) - 1;
107329
+ t.push(t0);
107330
+ t.push(tprev);
107331
+ t.push(tcurr);
107332
+ tprev = tcurr;
107333
+ }
106965
107334
  }
106966
107335
  }
106967
107336
  var positions = new Float32Array(pts);
@@ -109643,6 +110012,219 @@ var defaultFontMetrics = {
109643
110012
  glyphs,
109644
110013
  kerning
109645
110014
  };
110015
+ var DEFAULT_WEBSOCKET_CONFIG = {
110016
+ url: "",
110017
+ deserializer: function(e) {
110018
+ return JSON.parse(e.data);
110019
+ },
110020
+ serializer: function(value2) {
110021
+ return JSON.stringify(value2);
110022
+ }
110023
+ };
110024
+ var WEBSOCKETSUBJECT_INVALID_ERROR_OBJECT = "WebSocketSubject.error must be called with an object with an error code, and an optional reason: { code: number, reason: string }";
110025
+ var WebSocketSubject = function(_super) {
110026
+ __extends(WebSocketSubject2, _super);
110027
+ function WebSocketSubject2(urlConfigOrSource, destination) {
110028
+ var _this = _super.call(this) || this;
110029
+ _this._socket = null;
110030
+ if (urlConfigOrSource instanceof Observable) {
110031
+ _this.destination = destination;
110032
+ _this.source = urlConfigOrSource;
110033
+ } else {
110034
+ var config2 = _this._config = __assign({}, DEFAULT_WEBSOCKET_CONFIG);
110035
+ _this._output = new Subject();
110036
+ if (typeof urlConfigOrSource === "string") {
110037
+ config2.url = urlConfigOrSource;
110038
+ } else {
110039
+ for (var key2 in urlConfigOrSource) {
110040
+ if (urlConfigOrSource.hasOwnProperty(key2)) {
110041
+ config2[key2] = urlConfigOrSource[key2];
110042
+ }
110043
+ }
110044
+ }
110045
+ if (!config2.WebSocketCtor && WebSocket) {
110046
+ config2.WebSocketCtor = WebSocket;
110047
+ } else if (!config2.WebSocketCtor) {
110048
+ throw new Error("no WebSocket constructor can be found");
110049
+ }
110050
+ _this.destination = new ReplaySubject();
110051
+ }
110052
+ return _this;
110053
+ }
110054
+ WebSocketSubject2.prototype.lift = function(operator) {
110055
+ var sock = new WebSocketSubject2(this._config, this.destination);
110056
+ sock.operator = operator;
110057
+ sock.source = this;
110058
+ return sock;
110059
+ };
110060
+ WebSocketSubject2.prototype._resetState = function() {
110061
+ this._socket = null;
110062
+ if (!this.source) {
110063
+ this.destination = new ReplaySubject();
110064
+ }
110065
+ this._output = new Subject();
110066
+ };
110067
+ WebSocketSubject2.prototype.multiplex = function(subMsg, unsubMsg, messageFilter) {
110068
+ var self2 = this;
110069
+ return new Observable(function(observer) {
110070
+ try {
110071
+ self2.next(subMsg());
110072
+ } catch (err2) {
110073
+ observer.error(err2);
110074
+ }
110075
+ var subscription = self2.subscribe({
110076
+ next: function(x2) {
110077
+ try {
110078
+ if (messageFilter(x2)) {
110079
+ observer.next(x2);
110080
+ }
110081
+ } catch (err2) {
110082
+ observer.error(err2);
110083
+ }
110084
+ },
110085
+ error: function(err2) {
110086
+ return observer.error(err2);
110087
+ },
110088
+ complete: function() {
110089
+ return observer.complete();
110090
+ }
110091
+ });
110092
+ return function() {
110093
+ try {
110094
+ self2.next(unsubMsg());
110095
+ } catch (err2) {
110096
+ observer.error(err2);
110097
+ }
110098
+ subscription.unsubscribe();
110099
+ };
110100
+ });
110101
+ };
110102
+ WebSocketSubject2.prototype._connectSocket = function() {
110103
+ var _this = this;
110104
+ var _a2 = this._config, WebSocketCtor = _a2.WebSocketCtor, protocol = _a2.protocol, url = _a2.url, binaryType = _a2.binaryType;
110105
+ var observer = this._output;
110106
+ var socket = null;
110107
+ try {
110108
+ socket = protocol ? new WebSocketCtor(url, protocol) : new WebSocketCtor(url);
110109
+ this._socket = socket;
110110
+ if (binaryType) {
110111
+ this._socket.binaryType = binaryType;
110112
+ }
110113
+ } catch (e) {
110114
+ observer.error(e);
110115
+ return;
110116
+ }
110117
+ var subscription = new Subscription(function() {
110118
+ _this._socket = null;
110119
+ if (socket && socket.readyState === 1) {
110120
+ socket.close();
110121
+ }
110122
+ });
110123
+ socket.onopen = function(evt) {
110124
+ var _socket = _this._socket;
110125
+ if (!_socket) {
110126
+ socket.close();
110127
+ _this._resetState();
110128
+ return;
110129
+ }
110130
+ var openObserver = _this._config.openObserver;
110131
+ if (openObserver) {
110132
+ openObserver.next(evt);
110133
+ }
110134
+ var queue = _this.destination;
110135
+ _this.destination = Subscriber.create(function(x2) {
110136
+ if (socket.readyState === 1) {
110137
+ try {
110138
+ var serializer = _this._config.serializer;
110139
+ socket.send(serializer(x2));
110140
+ } catch (e) {
110141
+ _this.destination.error(e);
110142
+ }
110143
+ }
110144
+ }, function(err2) {
110145
+ var closingObserver = _this._config.closingObserver;
110146
+ if (closingObserver) {
110147
+ closingObserver.next(void 0);
110148
+ }
110149
+ if (err2 && err2.code) {
110150
+ socket.close(err2.code, err2.reason);
110151
+ } else {
110152
+ observer.error(new TypeError(WEBSOCKETSUBJECT_INVALID_ERROR_OBJECT));
110153
+ }
110154
+ _this._resetState();
110155
+ }, function() {
110156
+ var closingObserver = _this._config.closingObserver;
110157
+ if (closingObserver) {
110158
+ closingObserver.next(void 0);
110159
+ }
110160
+ socket.close();
110161
+ _this._resetState();
110162
+ });
110163
+ if (queue && queue instanceof ReplaySubject) {
110164
+ subscription.add(queue.subscribe(_this.destination));
110165
+ }
110166
+ };
110167
+ socket.onerror = function(e) {
110168
+ _this._resetState();
110169
+ observer.error(e);
110170
+ };
110171
+ socket.onclose = function(e) {
110172
+ if (socket === _this._socket) {
110173
+ _this._resetState();
110174
+ }
110175
+ var closeObserver = _this._config.closeObserver;
110176
+ if (closeObserver) {
110177
+ closeObserver.next(e);
110178
+ }
110179
+ if (e.wasClean) {
110180
+ observer.complete();
110181
+ } else {
110182
+ observer.error(e);
110183
+ }
110184
+ };
110185
+ socket.onmessage = function(e) {
110186
+ try {
110187
+ var deserializer = _this._config.deserializer;
110188
+ observer.next(deserializer(e));
110189
+ } catch (err2) {
110190
+ observer.error(err2);
110191
+ }
110192
+ };
110193
+ };
110194
+ WebSocketSubject2.prototype._subscribe = function(subscriber) {
110195
+ var _this = this;
110196
+ var source = this.source;
110197
+ if (source) {
110198
+ return source.subscribe(subscriber);
110199
+ }
110200
+ if (!this._socket) {
110201
+ this._connectSocket();
110202
+ }
110203
+ this._output.subscribe(subscriber);
110204
+ subscriber.add(function() {
110205
+ var _socket = _this._socket;
110206
+ if (_this._output.observers.length === 0) {
110207
+ if (_socket && (_socket.readyState === 1 || _socket.readyState === 0)) {
110208
+ _socket.close();
110209
+ }
110210
+ _this._resetState();
110211
+ }
110212
+ });
110213
+ return subscriber;
110214
+ };
110215
+ WebSocketSubject2.prototype.unsubscribe = function() {
110216
+ var _socket = this._socket;
110217
+ if (_socket && (_socket.readyState === 1 || _socket.readyState === 0)) {
110218
+ _socket.close();
110219
+ }
110220
+ this._resetState();
110221
+ _super.prototype.unsubscribe.call(this);
110222
+ };
110223
+ return WebSocketSubject2;
110224
+ }(AnonymousSubject);
110225
+ function webSocket(urlConfigOrSource) {
110226
+ return new WebSocketSubject(urlConfigOrSource);
110227
+ }
109646
110228
  const log = new Log();
109647
110229
  const cmapper = new colortables();
109648
110230
  function Niivue(options = {}) {
@@ -109678,7 +110260,9 @@ function Niivue(options = {}) {
109678
110260
  this.volumeTexture = null;
109679
110261
  this.drawTexture = null;
109680
110262
  this.drawBitmap = null;
109681
- this.drawUndoBitmap = null;
110263
+ this.maxDrawUndoBitmaps = 8;
110264
+ this.currentDrawUndoBitmap = this.maxDrawUndoBitmaps;
110265
+ this.drawUndoBitmaps = [];
109682
110266
  this.drawOpacity = 0.8;
109683
110267
  this.drawPenLocation = [NaN, NaN, NaN];
109684
110268
  this.drawPenAxCorSag = -1;
@@ -109812,6 +110396,12 @@ function Niivue(options = {}) {
109812
110396
  Frag: fragMeshToonShader
109813
110397
  }
109814
110398
  ];
110399
+ this.isController = false;
110400
+ this.isInSession = false;
110401
+ this.sessionKey = "";
110402
+ this.sessionUrl = "";
110403
+ this.serverConnection$ = null;
110404
+ this.interval$ = null;
109815
110405
  this.initialized = false;
109816
110406
  for (let prop in this.defaults) {
109817
110407
  this.opts[prop] = options[prop] === void 0 ? this.defaults[prop] : options[prop];
@@ -109902,6 +110492,85 @@ Niivue.prototype.sync = function() {
109902
110492
  }
109903
110493
  this.otherNV.drawScene();
109904
110494
  };
110495
+ Niivue.prototype.connectToServer = function(wsServerUrl, sessionName) {
110496
+ const url = new URL(wsServerUrl);
110497
+ url.pathname = "websockets";
110498
+ url.search = "?session=" + sessionName;
110499
+ this.serverConnection$ = webSocket(url.href);
110500
+ console.log(url.href);
110501
+ };
110502
+ Niivue.prototype.setUpdateInterval = function() {
110503
+ this.interval$ = interval(300);
110504
+ this.interval$.subscribe(() => {
110505
+ this.serverConnection$.next({
110506
+ op: "update",
110507
+ azimuth: this.scene.renderAzimuth,
110508
+ elevation: this.scene.renderElevation,
110509
+ clipPlane: this.scene.clipPlane,
110510
+ zoom: this.volScaleMultiplier,
110511
+ key: this.sessionKey
110512
+ });
110513
+ });
110514
+ };
110515
+ Niivue.prototype.subscribeToServer = function(sessionCreatedCallback, sessionJoinedCallback) {
110516
+ this.serverConnection$.subscribe({
110517
+ next: (msg2) => {
110518
+ switch (msg2["op"]) {
110519
+ case "update":
110520
+ this.scene.renderAzimuth = msg2["azimuth"];
110521
+ this.scene.renderElevation = msg2["elevation"];
110522
+ this.volScaleMultiplier = msg2["zoom"];
110523
+ this.scene.clipPlane = msg2["clipPlane"];
110524
+ this.drawScene();
110525
+ break;
110526
+ case "create":
110527
+ console.log(msg2);
110528
+ if (!msg2["isError"]) {
110529
+ this.isInSession = true;
110530
+ this.sessionKey = msg2["key"];
110531
+ this.setUpdateInterval();
110532
+ }
110533
+ if (sessionCreatedCallback) {
110534
+ sessionCreatedCallback(msg2["message"], msg2["url"], msg2["key"], msg2["isError"]);
110535
+ }
110536
+ break;
110537
+ case "join":
110538
+ this.isInSession = true;
110539
+ this.isController = msg2["isController"];
110540
+ if (this.isController) {
110541
+ this.setUpdateInterval();
110542
+ }
110543
+ if (sessionJoinedCallback) {
110544
+ sessionJoinedCallback(msg2["message"], msg2["url"], msg2["isController"]);
110545
+ }
110546
+ break;
110547
+ }
110548
+ },
110549
+ error: (err2) => console.log(err2),
110550
+ complete: () => console.log("complete")
110551
+ });
110552
+ };
110553
+ Niivue.prototype.createSession = function(wsServerUrl, sessionName, sessionCreatedCallback) {
110554
+ this.connectToServer(wsServerUrl, sessionName);
110555
+ this.subscribeToServer(sessionCreatedCallback);
110556
+ this.serverConnection$.next({
110557
+ op: "create"
110558
+ });
110559
+ };
110560
+ Niivue.prototype.joinSession = function(wsServerUrl, sessionName, key2, sessionJoinedCallback) {
110561
+ this.connectToServer(wsServerUrl, sessionName);
110562
+ this.subscribeToServer(null, sessionJoinedCallback);
110563
+ this.serverConnection$.next({
110564
+ op: "join",
110565
+ key: key2
110566
+ });
110567
+ };
110568
+ Niivue.prototype.closeSession = function() {
110569
+ this.interval$.complete();
110570
+ this.serverConnection$.complete();
110571
+ this.isInSession = false;
110572
+ this.isController = false;
110573
+ };
109905
110574
  Niivue.prototype.arrayEquals = function(a, b) {
109906
110575
  return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((val, index) => val === b[index]);
109907
110576
  };
@@ -109956,13 +110625,13 @@ Niivue.prototype.mouseRightButtonHandler = function(e) {
109956
110625
  this.dragClipPlaneStartDepthAziElev = this.scene.clipPlaneDepthAziElev;
109957
110626
  return;
109958
110627
  };
109959
- Niivue.prototype.calculateMinMaxVoxIdx = function(array) {
109960
- if (array.length > 2) {
110628
+ Niivue.prototype.calculateMinMaxVoxIdx = function(array2) {
110629
+ if (array2.length > 2) {
109961
110630
  throw new Error("array must not contain more than two values");
109962
110631
  }
109963
110632
  return [
109964
- Math.floor(Math.min(array[0], array[1])),
109965
- Math.floor(Math.max(array[0], array[1]))
110633
+ Math.floor(Math.min(array2[0], array2[1])),
110634
+ Math.floor(Math.max(array2[0], array2[1]))
109966
110635
  ];
109967
110636
  };
109968
110637
  function intensityRaw2Scaled(hdr, raw) {
@@ -110027,6 +110696,8 @@ Niivue.prototype.mouseUpListener = function() {
110027
110696
  this.scene.mouseButtonLeftDown = false;
110028
110697
  if (this.drawPenFillPts.length > 0)
110029
110698
  this.drawPenFilled();
110699
+ else if (this.drawPenAxCorSag >= 0)
110700
+ this.drawAddUndoBitmap();
110030
110701
  this.drawPenLocation = [NaN, NaN, NaN];
110031
110702
  this.drawPenAxCorSag = -1;
110032
110703
  if (this.isDragging) {
@@ -110340,9 +111011,112 @@ Niivue.prototype.getVolumeIndexByID = function(id) {
110340
111011
  }
110341
111012
  return -1;
110342
111013
  };
111014
+ function encodeRLE(data) {
111015
+ let dl = data.length;
111016
+ let dp = 0;
111017
+ let r = new Uint8Array(dl + Math.ceil(0.01 * dl));
111018
+ let rI = new Int8Array(r.buffer);
111019
+ let rp = 0;
111020
+ while (dp < dl) {
111021
+ let v = data[dp];
111022
+ dp++;
111023
+ let rl = 1;
111024
+ while (rl < 129 && dp < dl && data[dp] === v) {
111025
+ dp++;
111026
+ rl++;
111027
+ }
111028
+ if (rl > 1) {
111029
+ rI[rp] = -rl + 1;
111030
+ rp++;
111031
+ r[rp] = v;
111032
+ rp++;
111033
+ continue;
111034
+ }
111035
+ while (dp < dl) {
111036
+ if (rl > 127)
111037
+ break;
111038
+ if (dp + 2 < dl) {
111039
+ if (v !== data[dp] && data[dp + 2] === data[dp] && data[dp + 1] === data[dp])
111040
+ break;
111041
+ }
111042
+ v = data[dp];
111043
+ dp++;
111044
+ rl++;
111045
+ }
111046
+ r[rp] = rl - 1;
111047
+ rp++;
111048
+ for (let i2 = 0; i2 < rl; i2++) {
111049
+ r[rp] = data[dp - rl + i2];
111050
+ rp++;
111051
+ }
111052
+ }
111053
+ log.info("PackBits " + dl + " -> " + rp + " bytes (x" + dl / rp + ")");
111054
+ return r.slice(0, rp);
111055
+ }
111056
+ function decodeRLE(rle2, decodedlen) {
111057
+ let r = new Uint8Array(rle2.buffer);
111058
+ let rI = new Int8Array(r.buffer);
111059
+ let rp = 0;
111060
+ let d = new Uint8Array(decodedlen);
111061
+ let dp = 0;
111062
+ while (rp < r.length) {
111063
+ let hdr = rI[rp];
111064
+ rp++;
111065
+ if (hdr < 0) {
111066
+ let v = rI[rp];
111067
+ rp++;
111068
+ for (let i2 = 0; i2 < 1 - hdr; i2++) {
111069
+ d[dp] = v;
111070
+ dp++;
111071
+ }
111072
+ } else {
111073
+ for (let i2 = 0; i2 < hdr + 1; i2++) {
111074
+ d[dp] = rI[rp];
111075
+ rp++;
111076
+ dp++;
111077
+ }
111078
+ }
111079
+ }
111080
+ return d;
111081
+ }
111082
+ Niivue.prototype.drawAddUndoBitmap = async function(fnm) {
111083
+ if (!this.drawBitmap || this.drawBitmap.length < 1) {
111084
+ console.log("drawAddUndoBitmap error: No drawing open");
111085
+ return false;
111086
+ }
111087
+ this.currentDrawUndoBitmap++;
111088
+ if (this.currentDrawUndoBitmap >= this.maxDrawUndoBitmaps)
111089
+ this.currentDrawUndoBitmap = 0;
111090
+ this.drawUndoBitmaps[this.currentDrawUndoBitmap] = encodeRLE(this.drawBitmap);
111091
+ };
111092
+ Niivue.prototype.drawClearAllUndoBitmaps = async function() {
111093
+ this.currentDrawUndoBitmap = this.maxDrawUndoBitmaps;
111094
+ if (this.drawUndoBitmaps.length < 1)
111095
+ return;
111096
+ for (let i2 = this.drawUndoBitmaps.length - 1; i2 >= 0; i2--)
111097
+ array[i2] = [];
111098
+ };
111099
+ Niivue.prototype.drawUndo = function() {
111100
+ if (this.drawUndoBitmaps.length < 1) {
111101
+ console.log("undo bitmaps not loaded");
111102
+ return;
111103
+ }
111104
+ this.currentDrawUndoBitmap--;
111105
+ if (this.currentDrawUndoBitmap < 0)
111106
+ this.currentDrawUndoBitmap = this.drawUndoBitmaps.length - 1;
111107
+ if (this.currentDrawUndoBitmap >= this.drawUndoBitmaps.length)
111108
+ this.currentDrawUndoBitmap = 0;
111109
+ if (this.drawUndoBitmaps[this.currentDrawUndoBitmap].length < 2) {
111110
+ console.log("drawUndo is misbehaving");
111111
+ return;
111112
+ }
111113
+ this.drawBitmap = decodeRLE(this.drawUndoBitmaps[this.currentDrawUndoBitmap], this.drawBitmap.length);
111114
+ this.refreshDrawing(true);
111115
+ };
110343
111116
  Niivue.prototype.loadDrawing = async function(fnm) {
110344
111117
  if (this.drawBitmap)
110345
111118
  console.log("Overwriting open drawing!");
111119
+ this.drawClearAllUndoBitmaps();
110346
111120
  let volume = await NVImage.loadFromUrl({ url: fnm });
110347
111121
  let dims = volume.hdr.dims;
110348
111122
  if (dims[1] !== this.back.hdr.dims[1] || dims[2] !== this.back.hdr.dims[2] || dims[3] !== this.back.hdr.dims[3]) {
@@ -110353,7 +111127,6 @@ Niivue.prototype.loadDrawing = async function(fnm) {
110353
111127
  console.log("Drawings should be UINT8");
110354
111128
  let perm = volume.permRAS;
110355
111129
  let vx = dims[1] * dims[2] * dims[3];
110356
- this.drawUndoBitmap = null;
110357
111130
  this.drawBitmap = new Uint8Array(vx);
110358
111131
  this.drawTexture = this.r8Tex(this.drawTexture, this.gl.TEXTURE7, this.back.dims, true);
110359
111132
  let layout = [0, 0, 0];
@@ -110405,6 +111178,7 @@ Niivue.prototype.loadDrawing = async function(fnm) {
110405
111178
  }
110406
111179
  }
110407
111180
  }
111181
+ this.drawAddUndoBitmap();
110408
111182
  this.refreshDrawing(false);
110409
111183
  this.drawScene();
110410
111184
  };
@@ -110698,6 +111472,8 @@ Niivue.prototype.setScale = function(scale2) {
110698
111472
  };
110699
111473
  Niivue.prototype.setClipPlaneColor = function(color) {
110700
111474
  this.opts.clipPlaneColor = color;
111475
+ this.renderShader.use(this.gl);
111476
+ this.gl.uniform4fv(this.renderShader.uniforms["clipPlaneColor"], this.opts.clipPlaneColor);
110701
111477
  this.drawScene();
110702
111478
  };
110703
111479
  Niivue.prototype.overlayRGBA = function(volume) {
@@ -110841,7 +111617,8 @@ Niivue.prototype.createEmptyDrawing = function() {
110841
111617
  return;
110842
111618
  let vx = this.back.dims[1] * this.back.dims[2] * this.back.dims[3];
110843
111619
  this.drawBitmap = new Uint8Array(vx);
110844
- this.drawUndoBitmap = null;
111620
+ this.drawClearAllUndoBitmaps();
111621
+ this.drawAddUndoBitmap();
110845
111622
  this.drawTexture = this.r8Tex(this.drawTexture, this.gl.TEXTURE7, this.back.dims, true);
110846
111623
  this.refreshDrawing(false);
110847
111624
  };
@@ -110918,16 +111695,6 @@ function img2ras16(volume) {
110918
111695
  }
110919
111696
  return img16;
110920
111697
  }
110921
- Niivue.prototype.drawUndo = function() {
110922
- let hdr = this.back.hdr;
110923
- let nv = hdr.dims[1] * hdr.dims[2] * hdr.dims[3];
110924
- if (this.drawUndoBitmap.length !== nv || this.drawBitmap.length !== nv) {
110925
- console.log("bitmap dims are wrong");
110926
- return;
110927
- }
110928
- this.drawBitmap = this.drawUndoBitmap.slice();
110929
- this.refreshDrawing(true);
110930
- };
110931
111698
  Niivue.prototype.drawGrowCut = function() {
110932
111699
  let hdr = this.back.hdr;
110933
111700
  let nv = hdr.dims[1] * hdr.dims[2] * hdr.dims[3];
@@ -110935,7 +111702,6 @@ Niivue.prototype.drawGrowCut = function() {
110935
111702
  console.log("bitmap dims are wrong");
110936
111703
  return;
110937
111704
  }
110938
- this.drawUndoBitmap = this.drawBitmap.slice();
110939
111705
  let gl = this.gl;
110940
111706
  let fb = gl.createFramebuffer();
110941
111707
  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
@@ -110948,16 +111714,19 @@ Niivue.prototype.drawGrowCut = function() {
110948
111714
  img16[i2] = this.drawBitmap[i2];
110949
111715
  let label0 = this.r16Tex(null, gl.TEXTURE6, this.back.dims, img16);
110950
111716
  let label1 = this.r16Tex(null, gl.TEXTURE7, this.back.dims, img16);
111717
+ let kMAX_STRENGTH = 1e4;
110951
111718
  for (let i2 = 1; i2 < nv; i2++)
110952
111719
  if (img16[i2] > 0)
110953
- img16[i2] = 1e4;
111720
+ img16[i2] = kMAX_STRENGTH;
110954
111721
  let strength0 = this.r16Tex(null, gl.TEXTURE4, this.back.dims, img16);
110955
111722
  let strength1 = this.r16Tex(null, gl.TEXTURE5, this.back.dims, img16);
110956
111723
  this.gl.bindVertexArray(this.genericVAO);
110957
111724
  let shader = this.growCutShader;
110958
111725
  shader.use(gl);
111726
+ let iterations = 128;
111727
+ gl.uniform1i(shader.uniforms["finalPass"], 0);
110959
111728
  gl.uniform1i(shader.uniforms["inputTexture0"], 3);
110960
- for (let j = 0; j < 45; j++) {
111729
+ for (let j = 0; j < iterations; j++) {
110961
111730
  gl.uniform1i(shader.uniforms["inputTexture1"], 6);
110962
111731
  gl.uniform1i(shader.uniforms["inputTexture2"], 4);
110963
111732
  for (let i2 = 0; i2 < this.back.dims[3]; i2++) {
@@ -110971,6 +111740,8 @@ Niivue.prototype.drawGrowCut = function() {
110971
111740
  console.error("Incomplete framebuffer");
110972
111741
  this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
110973
111742
  }
111743
+ if (j === iterations - 1)
111744
+ gl.uniform1i(shader.uniforms["finalPass"], 1);
110974
111745
  gl.uniform1i(shader.uniforms["inputTexture1"], 7);
110975
111746
  gl.uniform1i(shader.uniforms["inputTexture2"], 5);
110976
111747
  for (let i2 = 0; i2 < this.back.dims[3]; i2++) {
@@ -110986,8 +111757,8 @@ Niivue.prototype.drawGrowCut = function() {
110986
111757
  }
110987
111758
  }
110988
111759
  gl.drawBuffers([gl.COLOR_ATTACHMENT0]);
110989
- let readAttach = gl.COLOR_ATTACHMENT0;
110990
- let readTex = label1;
111760
+ let readAttach = gl.COLOR_ATTACHMENT1;
111761
+ let readTex = label0;
110991
111762
  gl.readBuffer(readAttach);
110992
111763
  const format = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT);
110993
111764
  const type2 = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE);
@@ -111023,6 +111794,7 @@ Niivue.prototype.drawGrowCut = function() {
111023
111794
  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
111024
111795
  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
111025
111796
  gl.deleteFramebuffer(fb);
111797
+ this.drawAddUndoBitmap();
111026
111798
  this.refreshDrawing(true);
111027
111799
  };
111028
111800
  Niivue.prototype.drawPt = function(x2, y, z, penValue) {
@@ -111106,6 +111878,74 @@ Niivue.prototype.drawLine = function(ptA, ptB, penValue) {
111106
111878
  }
111107
111879
  }
111108
111880
  };
111881
+ Niivue.prototype.drawFloodFill = function(seedXYZ, newColor = 0) {
111882
+ newColor = Math.abs(newColor);
111883
+ let dims = [this.back.dims[1], this.back.dims[2], this.back.dims[3]];
111884
+ if (seedXYZ[0] < 0 || seedXYZ[1] < 0 || seedXYZ[2] < 0)
111885
+ return;
111886
+ if (seedXYZ[0] >= dims[0] || seedXYZ[1] >= dims[1] || seedXYZ[2] >= dims[2])
111887
+ return;
111888
+ let nx = dims[0];
111889
+ let nxy = nx * dims[1];
111890
+ let nxyz = nxy * dims[2];
111891
+ let img = this.drawBitmap.slice();
111892
+ if (img.length !== nxy * dims[2])
111893
+ return;
111894
+ function xyz2vx(pt) {
111895
+ return pt[0] + pt[1] * nx + pt[2] * nxy;
111896
+ }
111897
+ function vx2xyz(vx) {
111898
+ let Z = Math.floor(vx / nxy);
111899
+ let Y = Math.floor((vx - Z * nxy) / nx);
111900
+ let X = Math.floor(vx % nx);
111901
+ return [X, Y, Z];
111902
+ }
111903
+ let seedVx = xyz2vx(seedXYZ);
111904
+ let seedColor = img[seedVx];
111905
+ if (seedColor === newColor) {
111906
+ console.log("drawFloodFill selected voxel is already desired color");
111907
+ return;
111908
+ }
111909
+ for (let i2 = 1; i2 < nxyz; i2++) {
111910
+ img[i2] = 0;
111911
+ if (this.drawBitmap[i2] === seedColor)
111912
+ img[i2] = 1;
111913
+ }
111914
+ let Q = [];
111915
+ Q.push(seedVx);
111916
+ img[seedVx] = 2;
111917
+ while (Q.length > 0) {
111918
+ let testNeighbor = function(offset) {
111919
+ let xyzN = xyz.slice();
111920
+ xyzN[0] += offset[0];
111921
+ xyzN[1] += offset[1];
111922
+ xyzN[2] += offset[2];
111923
+ if (xyzN[0] < 0 || xyzN[1] < 0 || xyzN[2] < 0)
111924
+ return;
111925
+ if (xyzN[0] >= dims[0] || xyzN[1] >= dims[1] || xyzN[2] >= dims[2])
111926
+ return;
111927
+ let vxT = xyz2vx(xyzN);
111928
+ if (img[vxT] !== 1)
111929
+ return;
111930
+ img[vxT] = 2;
111931
+ Q.push(vxT);
111932
+ };
111933
+ let vx = Q[0];
111934
+ Q.shift();
111935
+ let xyz = vx2xyz(vx);
111936
+ testNeighbor([0, 0, -1]);
111937
+ testNeighbor([0, 0, 1]);
111938
+ testNeighbor([0, -1, 0]);
111939
+ testNeighbor([0, 1, 0]);
111940
+ testNeighbor([-1, 0, 0]);
111941
+ testNeighbor([1, 0, 0]);
111942
+ }
111943
+ for (let i2 = 1; i2 < nxyz; i2++)
111944
+ if (img[i2] === 2)
111945
+ this.drawBitmap[i2] = newColor;
111946
+ this.drawAddUndoBitmap();
111947
+ this.refreshDrawing(false);
111948
+ };
111109
111949
  Niivue.prototype.drawPenFilled = function() {
111110
111950
  let nPts = this.drawPenFillPts.length;
111111
111951
  if (nPts < 2) {
@@ -111221,15 +112061,17 @@ Niivue.prototype.drawPenFilled = function() {
111221
112061
  }
111222
112062
  }
111223
112063
  }
111224
- if (!this.drawFillOverwrites && this.drawUndoBitmap.length === this.drawBitmap.length) {
111225
- let nv = this.drawUndoBitmap.length;
112064
+ if (!this.drawFillOverwrites && this.drawUndoBitmaps[this.currentDrawUndoBitmap].length > 0) {
112065
+ let nv = this.drawBitmap.length;
112066
+ let bmp = decodeRLE(this.drawUndoBitmaps[this.currentDrawUndoBitmap], nv);
111226
112067
  for (let i2 = 0; i2 < nv; i2++) {
111227
- if (this.drawUndoBitmap[i2] === 0)
112068
+ if (bmp[i2] === 0)
111228
112069
  continue;
111229
- this.drawBitmap[i2] = this.drawUndoBitmap[i2];
112070
+ this.drawBitmap[i2] = bmp[i2];
111230
112071
  }
111231
112072
  }
111232
112073
  this.drawPenFillPts = [];
112074
+ this.drawAddUndoBitmap();
111233
112075
  this.refreshDrawing(false);
111234
112076
  };
111235
112077
  Niivue.prototype.closeDrawing = function() {
@@ -111947,11 +112789,14 @@ Niivue.prototype.mouseClick = function(x2, y, posChange = 0, isDelta = true) {
111947
112789
  }
111948
112790
  if (this.opts.drawingEnabled) {
111949
112791
  let pt = this.frac2vox(this.scene.crosshairPos);
112792
+ if (this.opts.penValue < 0 || Object.is(this.opts.penValue, -0)) {
112793
+ this.drawFloodFill(pt, Math.abs(this.opts.penValue));
112794
+ return;
112795
+ }
111950
112796
  if (isNaN(this.drawPenLocation[0])) {
111951
112797
  this.drawPenAxCorSag = axCorSag;
111952
112798
  this.drawPenFillPts = [];
111953
112799
  this.drawPt(...pt, this.opts.penValue);
111954
- this.drawUndoBitmap = this.drawBitmap.slice();
111955
112800
  } else {
111956
112801
  if (pt[0] === this.drawPenLocation[0] && pt[1] === this.drawPenLocation[1] && pt[2] === this.drawPenLocation[2])
111957
112802
  return;
@@ -112107,9 +112952,12 @@ Niivue.prototype.setInterpolation = function(isNearest) {
112107
112952
  this.updateInterpolation(1);
112108
112953
  this.drawScene();
112109
112954
  };
112110
- Niivue.prototype.calculateMvpMatrixX = function() {
112111
- let whratio = this.gl.canvas.clientWidth / this.gl.canvas.clientHeight;
112112
- let scale2 = this.furthestFromPivot;
112955
+ Niivue.prototype.calculateMvpMatrixX = function(leftTopWidthHeight) {
112956
+ let gl = this.gl;
112957
+ gl.viewport(leftTopWidthHeight[0], leftTopWidthHeight[1], leftTopWidthHeight[2], leftTopWidthHeight[3]);
112958
+ let whratio = leftTopWidthHeight[2] / leftTopWidthHeight[3];
112959
+ console.log(">>", this.back.dimsRAS, this.back.matRAS);
112960
+ let scale2 = this.furthestFromPivot * 0.5;
112113
112961
  let origin = [0, 0, 0];
112114
112962
  let projectionMatrix = create$2();
112115
112963
  if (whratio < 1)
@@ -112140,7 +112988,7 @@ Niivue.prototype.drawMesh3DX = function(isDepthTest = true, alpha = 1, leftTopWi
112140
112988
  return;
112141
112989
  let gl = this.gl;
112142
112990
  let m, modelMtx, normMtx;
112143
- [m, modelMtx, normMtx] = this.calculateMvpMatrixX(this.volumeObject3D, leftTopWidthHeight);
112991
+ [m, modelMtx, normMtx] = this.calculateMvpMatrixX(leftTopWidthHeight);
112144
112992
  gl.enable(gl.DEPTH_TEST);
112145
112993
  gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
112146
112994
  gl.disable(gl.BLEND);
@@ -112273,7 +113121,6 @@ Niivue.prototype.draw2D = function(leftTopWidthHeight, axCorSag) {
112273
113121
  ], "S");
112274
113122
  if (axCorSag !== this.sliceTypeAxial)
112275
113123
  return;
112276
- this.setPivot3D();
112277
113124
  gl.viewport(leftTopWidthHeight[0], leftTopWidthHeight[1], leftTopWidthHeight[2], leftTopWidthHeight[3]);
112278
113125
  gl.enable(gl.DEPTH_TEST);
112279
113126
  gl.depthFunc(gl.ALWAYS);