@niivue/niivue 0.20.1 → 0.22.2
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/README.md +5 -17
- package/dist/niivue.es.js +1034 -579
- package/dist/niivue.umd.js +191 -164
- package/package.json +2 -2
- package/src/index.html +8 -4
- package/src/niivue-object3D.js +153 -0
- package/src/niivue.js +516 -176
- package/src/nvimage.js +233 -208
- package/src/shader-srcs.js +176 -143
package/dist/niivue.es.js
CHANGED
|
@@ -97,7 +97,7 @@ function create$2() {
|
|
|
97
97
|
out[15] = 1;
|
|
98
98
|
return out;
|
|
99
99
|
}
|
|
100
|
-
function clone(a) {
|
|
100
|
+
function clone$1(a) {
|
|
101
101
|
var out = new ARRAY_TYPE(16);
|
|
102
102
|
out[0] = a[0];
|
|
103
103
|
out[1] = a[1];
|
|
@@ -117,7 +117,7 @@ function clone(a) {
|
|
|
117
117
|
out[15] = a[15];
|
|
118
118
|
return out;
|
|
119
119
|
}
|
|
120
|
-
function copy(out, a) {
|
|
120
|
+
function copy$1(out, a) {
|
|
121
121
|
out[0] = a[0];
|
|
122
122
|
out[1] = a[1];
|
|
123
123
|
out[2] = a[2];
|
|
@@ -424,6 +424,19 @@ function create$1() {
|
|
|
424
424
|
}
|
|
425
425
|
return out;
|
|
426
426
|
}
|
|
427
|
+
function clone(a) {
|
|
428
|
+
var out = new ARRAY_TYPE(3);
|
|
429
|
+
out[0] = a[0];
|
|
430
|
+
out[1] = a[1];
|
|
431
|
+
out[2] = a[2];
|
|
432
|
+
return out;
|
|
433
|
+
}
|
|
434
|
+
function length(a) {
|
|
435
|
+
var x = a[0];
|
|
436
|
+
var y = a[1];
|
|
437
|
+
var z = a[2];
|
|
438
|
+
return Math.hypot(x, y, z);
|
|
439
|
+
}
|
|
427
440
|
function fromValues$1(x, y, z) {
|
|
428
441
|
var out = new ARRAY_TYPE(3);
|
|
429
442
|
out[0] = x;
|
|
@@ -431,25 +444,80 @@ function fromValues$1(x, y, z) {
|
|
|
431
444
|
out[2] = z;
|
|
432
445
|
return out;
|
|
433
446
|
}
|
|
447
|
+
function copy(out, a) {
|
|
448
|
+
out[0] = a[0];
|
|
449
|
+
out[1] = a[1];
|
|
450
|
+
out[2] = a[2];
|
|
451
|
+
return out;
|
|
452
|
+
}
|
|
453
|
+
function add$1(out, a, b) {
|
|
454
|
+
out[0] = a[0] + b[0];
|
|
455
|
+
out[1] = a[1] + b[1];
|
|
456
|
+
out[2] = a[2] + b[2];
|
|
457
|
+
return out;
|
|
458
|
+
}
|
|
434
459
|
function subtract(out, a, b) {
|
|
435
460
|
out[0] = a[0] - b[0];
|
|
436
461
|
out[1] = a[1] - b[1];
|
|
437
462
|
out[2] = a[2] - b[2];
|
|
438
463
|
return out;
|
|
439
464
|
}
|
|
465
|
+
function min$Q(out, a, b) {
|
|
466
|
+
out[0] = Math.min(a[0], b[0]);
|
|
467
|
+
out[1] = Math.min(a[1], b[1]);
|
|
468
|
+
out[2] = Math.min(a[2], b[2]);
|
|
469
|
+
return out;
|
|
470
|
+
}
|
|
471
|
+
function max$Q(out, a, b) {
|
|
472
|
+
out[0] = Math.max(a[0], b[0]);
|
|
473
|
+
out[1] = Math.max(a[1], b[1]);
|
|
474
|
+
out[2] = Math.max(a[2], b[2]);
|
|
475
|
+
return out;
|
|
476
|
+
}
|
|
477
|
+
function negate(out, a) {
|
|
478
|
+
out[0] = -a[0];
|
|
479
|
+
out[1] = -a[1];
|
|
480
|
+
out[2] = -a[2];
|
|
481
|
+
return out;
|
|
482
|
+
}
|
|
440
483
|
function normalize(out, a) {
|
|
441
484
|
var x = a[0];
|
|
442
485
|
var y = a[1];
|
|
443
486
|
var z = a[2];
|
|
444
|
-
var
|
|
445
|
-
if (
|
|
446
|
-
|
|
487
|
+
var len2 = x * x + y * y + z * z;
|
|
488
|
+
if (len2 > 0) {
|
|
489
|
+
len2 = 1 / Math.sqrt(len2);
|
|
447
490
|
}
|
|
448
|
-
out[0] = a[0] *
|
|
449
|
-
out[1] = a[1] *
|
|
450
|
-
out[2] = a[2] *
|
|
491
|
+
out[0] = a[0] * len2;
|
|
492
|
+
out[1] = a[1] * len2;
|
|
493
|
+
out[2] = a[2] * len2;
|
|
494
|
+
return out;
|
|
495
|
+
}
|
|
496
|
+
function dot(a, b) {
|
|
497
|
+
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
498
|
+
}
|
|
499
|
+
function cross(out, a, b) {
|
|
500
|
+
var ax = a[0], ay = a[1], az = a[2];
|
|
501
|
+
var bx = b[0], by = b[1], bz = b[2];
|
|
502
|
+
out[0] = ay * bz - az * by;
|
|
503
|
+
out[1] = az * bx - ax * bz;
|
|
504
|
+
out[2] = ax * by - ay * bx;
|
|
505
|
+
return out;
|
|
506
|
+
}
|
|
507
|
+
function lerp(out, a, b, t) {
|
|
508
|
+
var ax = a[0];
|
|
509
|
+
var ay = a[1];
|
|
510
|
+
var az = a[2];
|
|
511
|
+
out[0] = ax + t * (b[0] - ax);
|
|
512
|
+
out[1] = ay + t * (b[1] - ay);
|
|
513
|
+
out[2] = az + t * (b[2] - az);
|
|
451
514
|
return out;
|
|
452
515
|
}
|
|
516
|
+
function angle(a, b) {
|
|
517
|
+
var ax = a[0], ay = a[1], az = a[2], bx = b[0], by = b[1], bz = b[2], mag1 = Math.sqrt(ax * ax + ay * ay + az * az), mag2 = Math.sqrt(bx * bx + by * by + bz * bz), mag = mag1 * mag2, cosine = mag && dot(a, b) / mag;
|
|
518
|
+
return Math.acos(Math.min(Math.max(cosine, -1), 1));
|
|
519
|
+
}
|
|
520
|
+
var len = length;
|
|
453
521
|
(function() {
|
|
454
522
|
var vec = create$1();
|
|
455
523
|
return function(a, stride, offset, count, fn, arg) {
|
|
@@ -550,16 +618,53 @@ var mul = multiply;
|
|
|
550
618
|
var vertRenderShader = `#version 300 es
|
|
551
619
|
#line 4
|
|
552
620
|
layout(location=0) in vec3 pos;
|
|
553
|
-
in vec3 texCoords;
|
|
621
|
+
layout(location=1) in vec3 texCoords;
|
|
554
622
|
uniform mat4 mvpMtx;
|
|
555
623
|
out vec3 vColor;
|
|
556
|
-
|
|
557
624
|
void main(void) {
|
|
558
625
|
gl_Position = mvpMtx * vec4(pos, 1.0); //vec4(2.0 * (pos.xyz - 0.5), 1.0);
|
|
559
626
|
vColor = texCoords;
|
|
560
627
|
}`;
|
|
628
|
+
const kRenderFunc = `vec3 GetBackPosition(vec3 startPositionTex) {
|
|
629
|
+
vec3 startPosition = startPositionTex * volScale;
|
|
630
|
+
vec3 invR = 1.0 / rayDir;
|
|
631
|
+
vec3 tbot = invR * (vec3(0.0)-startPosition);
|
|
632
|
+
vec3 ttop = invR * (volScale-startPosition);
|
|
633
|
+
vec3 tmax = max(ttop, tbot);
|
|
634
|
+
vec2 t = min(tmax.xx, tmax.yz);
|
|
635
|
+
vec3 endPosition = startPosition + (rayDir * min(t.x, t.y));
|
|
636
|
+
//convert world position back to texture position:
|
|
637
|
+
endPosition = endPosition / volScale;
|
|
638
|
+
return endPosition;
|
|
639
|
+
}
|
|
640
|
+
vec4 applyClip (vec3 dir, inout vec4 samplePos, inout float len, inout bool isClip) {
|
|
641
|
+
float cdot = dot(dir,clipPlane.xyz);
|
|
642
|
+
isClip = false;
|
|
643
|
+
if ((clipPlane.a > 1.0) || (cdot == 0.0)) return samplePos;
|
|
644
|
+
bool frontface = (cdot > 0.0);
|
|
645
|
+
float clipThick = 2.0;
|
|
646
|
+
float dis = (-clipPlane.a - dot(clipPlane.xyz, samplePos.xyz-0.5)) / cdot;
|
|
647
|
+
float disBackFace = (-(clipPlane.a-clipThick) - dot(clipPlane.xyz, samplePos.xyz-0.5)) / cdot;
|
|
648
|
+
if (((frontface) && (dis >= len)) || ((!frontface) && (dis <= 0.0))) {
|
|
649
|
+
samplePos.a = len + 1.0;
|
|
650
|
+
return samplePos;
|
|
651
|
+
}
|
|
652
|
+
if (frontface) {
|
|
653
|
+
dis = max(0.0, dis);
|
|
654
|
+
samplePos = vec4(samplePos.xyz+dir * dis, dis);
|
|
655
|
+
if (dis > 0.0) isClip = true;
|
|
656
|
+
len = min(disBackFace, len);
|
|
657
|
+
}
|
|
658
|
+
if (!frontface) {
|
|
659
|
+
len = min(dis, len);
|
|
660
|
+
disBackFace = max(0.0, disBackFace);
|
|
661
|
+
if (len == dis) isClip = true;
|
|
662
|
+
samplePos = vec4(samplePos.xyz+dir * disBackFace, disBackFace);
|
|
663
|
+
}
|
|
664
|
+
return samplePos;
|
|
665
|
+
}`;
|
|
561
666
|
var fragRenderShader = `#version 300 es
|
|
562
|
-
#line
|
|
667
|
+
#line 14
|
|
563
668
|
precision highp int;
|
|
564
669
|
precision highp float;
|
|
565
670
|
uniform vec3 rayDir;
|
|
@@ -569,65 +674,46 @@ uniform vec4 clipPlane;
|
|
|
569
674
|
uniform highp sampler3D volume, overlay;
|
|
570
675
|
uniform float overlays;
|
|
571
676
|
uniform float backOpacity;
|
|
677
|
+
uniform mat4 mvpMtx;
|
|
678
|
+
uniform mat4 matRAS;
|
|
679
|
+
uniform vec4 clipPlaneColor;
|
|
572
680
|
in vec3 vColor;
|
|
573
681
|
out vec4 fColor;
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
vec3
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
return endPosition;
|
|
587
|
-
}
|
|
588
|
-
vec4 applyClip (vec3 dir, inout vec4 samplePos, inout float len) {
|
|
589
|
-
float cdot = dot(dir,clipPlane.xyz);
|
|
590
|
-
if ((clipPlane.a > 1.0) || (cdot == 0.0)) return samplePos;
|
|
591
|
-
bool frontface = (cdot > 0.0);
|
|
592
|
-
float clipThick = 2.0;
|
|
593
|
-
float dis = (-clipPlane.a - dot(clipPlane.xyz, samplePos.xyz-0.5)) / cdot;
|
|
594
|
-
float disBackFace = (-(clipPlane.a-clipThick) - dot(clipPlane.xyz, samplePos.xyz-0.5)) / cdot;
|
|
595
|
-
if (((frontface) && (dis >= len)) || ((!frontface) && (dis <= 0.0))) {
|
|
596
|
-
samplePos.a = len + 1.0;
|
|
597
|
-
return samplePos;
|
|
598
|
-
}
|
|
599
|
-
if (frontface) {
|
|
600
|
-
dis = max(0.0, dis);
|
|
601
|
-
samplePos = vec4(samplePos.xyz+dir * dis, dis);
|
|
602
|
-
len = min(disBackFace, len);
|
|
603
|
-
}
|
|
604
|
-
if (!frontface) {
|
|
605
|
-
len = min(dis, len);
|
|
606
|
-
disBackFace = max(0.0, disBackFace);
|
|
607
|
-
samplePos = vec4(samplePos.xyz+dir * disBackFace, disBackFace);
|
|
608
|
-
}
|
|
609
|
-
return samplePos;
|
|
682
|
+
` + kRenderFunc + `
|
|
683
|
+
float frac2ndc(vec3 frac) {
|
|
684
|
+
//https://stackoverflow.com/questions/7777913/how-to-render-depth-linearly-in-modern-opengl-with-gl-fragcoord-z-in-fragment-sh
|
|
685
|
+
vec4 pos = vec4(frac.xyz, 1.0); //fraction
|
|
686
|
+
vec4 dim = vec4(vec3(textureSize(volume, 0)), 1.0);
|
|
687
|
+
pos = pos * dim;
|
|
688
|
+
vec4 shim = vec4(-0.5, -0.5, -0.5, 0.0);
|
|
689
|
+
pos += shim;
|
|
690
|
+
vec4 mm = transpose(matRAS) * pos;
|
|
691
|
+
float z_ndc = (mvpMtx * vec4(mm.xyz, 1.0)).z;
|
|
692
|
+
return (z_ndc + 1.0) / 2.0;
|
|
693
|
+
|
|
610
694
|
}
|
|
611
695
|
void main() {
|
|
612
|
-
|
|
696
|
+
fColor = vec4(0.0,0.0,0.0,0.0);
|
|
613
697
|
//fColor = vec4(vColor.rgb, 1.0); return;
|
|
614
|
-
// fColor = texture(volume, vColor.xyz);
|
|
615
|
-
// return;
|
|
616
698
|
vec3 start = vColor;
|
|
699
|
+
gl_FragDepth = 0.0;
|
|
617
700
|
vec3 backPosition = GetBackPosition(start);
|
|
618
701
|
// fColor = vec4(backPosition, 1.0); return;
|
|
619
|
-
|
|
620
|
-
|
|
702
|
+
vec3 dir = backPosition - start;
|
|
703
|
+
float len = length(dir);
|
|
621
704
|
float lenVox = length((texVox * start) - (texVox * backPosition));
|
|
622
|
-
if (lenVox < 0.5)
|
|
705
|
+
if ((lenVox < 0.5) || (len > 3.0)) { //length limit for parallel rays
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
623
708
|
float sliceSize = len / lenVox; //e.g. if ray length is 1.0 and traverses 50 voxels, each voxel is 0.02 in unit cube
|
|
624
709
|
float stepSize = sliceSize; //quality: larger step is faster traversal, but fewer samples
|
|
625
710
|
float opacityCorrection = stepSize/sliceSize;
|
|
626
|
-
|
|
711
|
+
dir = normalize(dir);
|
|
627
712
|
vec4 deltaDir = vec4(dir.xyz * stepSize, stepSize);
|
|
628
713
|
vec4 samplePos = vec4(start.xyz, 0.0); //ray position
|
|
629
714
|
float lenNoClip = len;
|
|
630
|
-
|
|
715
|
+
bool isClip = false;
|
|
716
|
+
vec4 clipPos = applyClip(dir, samplePos, len, isClip);
|
|
631
717
|
//start: OPTIONAL fast pass: rapid traversal until first hit
|
|
632
718
|
float stepSizeFast = sliceSize * 1.9;
|
|
633
719
|
vec4 deltaDirFast = vec4(dir.xyz * stepSizeFast, stepSizeFast);
|
|
@@ -636,21 +722,29 @@ void main() {
|
|
|
636
722
|
if (val > 0.01) break;
|
|
637
723
|
samplePos += deltaDirFast; //advance ray position
|
|
638
724
|
}
|
|
639
|
-
|
|
640
|
-
|
|
725
|
+
if ((samplePos.a >= len) && (overlays < 1.0)) {
|
|
726
|
+
if (isClip)
|
|
727
|
+
fColor += clipPlaneColor;
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
730
|
+
fColor = vec4(1.0, 1.0, 1.0, 1.0);
|
|
731
|
+
//gl_FragDepth = frac2ndc(samplePos.xyz); //crude due to fast pass resolution
|
|
641
732
|
samplePos -= deltaDirFast;
|
|
642
733
|
if (samplePos.a < 0.0)
|
|
643
734
|
vec4 samplePos = vec4(start.xyz, 0.0); //ray position
|
|
644
735
|
//end: fast pass
|
|
645
736
|
vec4 colAcc = vec4(0.0,0.0,0.0,0.0);
|
|
737
|
+
vec4 firstHit = colAcc;
|
|
646
738
|
const float earlyTermination = 0.95;
|
|
647
739
|
float backNearest = len; //assume no hit
|
|
648
|
-
|
|
649
|
-
|
|
740
|
+
float ran = fract(sin(gl_FragCoord.x * 12.9898 + gl_FragCoord.y * 78.233) * 43758.5453);
|
|
741
|
+
samplePos += deltaDir * ran; //jitter ray
|
|
650
742
|
while (samplePos.a <= len) {
|
|
651
743
|
vec4 colorSample = texture(volume, samplePos.xyz);
|
|
652
744
|
samplePos += deltaDir; //advance ray position
|
|
653
745
|
if (colorSample.a < 0.01) continue;
|
|
746
|
+
if (firstHit.a == 0.0)
|
|
747
|
+
firstHit = samplePos;
|
|
654
748
|
backNearest = min(backNearest, samplePos.a);
|
|
655
749
|
colorSample.a = 1.0-pow((1.0 - colorSample.a), opacityCorrection);
|
|
656
750
|
colorSample.rgb *= colorSample.a;
|
|
@@ -658,13 +752,15 @@ void main() {
|
|
|
658
752
|
if ( colAcc.a > earlyTermination )
|
|
659
753
|
break;
|
|
660
754
|
}
|
|
755
|
+
if (firstHit.a != 0.0)
|
|
756
|
+
gl_FragDepth = frac2ndc(firstHit.xyz);
|
|
661
757
|
colAcc.a = (colAcc.a / earlyTermination) * backOpacity;
|
|
662
758
|
fColor = colAcc;
|
|
663
759
|
if (overlays < 1.0) return;
|
|
664
760
|
//overlay pass
|
|
665
761
|
len = lenNoClip;
|
|
666
762
|
samplePos = vec4(start.xyz, 0.0); //ray position
|
|
667
|
-
|
|
763
|
+
//start: OPTIONAL fast pass: rapid traversal until first hit
|
|
668
764
|
stepSizeFast = sliceSize * 1.9;
|
|
669
765
|
deltaDirFast = vec4(dir.xyz * stepSizeFast, stepSizeFast);
|
|
670
766
|
while (samplePos.a <= len) {
|
|
@@ -672,7 +768,11 @@ void main() {
|
|
|
672
768
|
if (val > 0.01) break;
|
|
673
769
|
samplePos += deltaDirFast; //advance ray position
|
|
674
770
|
}
|
|
675
|
-
if (samplePos.a
|
|
771
|
+
if (samplePos.a >= len) {
|
|
772
|
+
if (isClip && (fColor.a == 0.0))
|
|
773
|
+
fColor += clipPlaneColor;
|
|
774
|
+
return;
|
|
775
|
+
}
|
|
676
776
|
samplePos -= deltaDirFast;
|
|
677
777
|
if (samplePos.a < 0.0)
|
|
678
778
|
vec4 samplePos = vec4(start.xyz, 0.0); //ray position
|
|
@@ -848,6 +948,55 @@ uniform highp isampler3D intensityVol;
|
|
|
848
948
|
var fragOrientShaderF = `#version 300 es
|
|
849
949
|
uniform highp sampler3D intensityVol;
|
|
850
950
|
`;
|
|
951
|
+
var fragOrientShaderAtlas = `#line 309
|
|
952
|
+
precision highp int;
|
|
953
|
+
precision highp float;
|
|
954
|
+
in vec2 TexCoord;
|
|
955
|
+
out vec4 FragColor;
|
|
956
|
+
uniform float coordZ;
|
|
957
|
+
uniform float layer;
|
|
958
|
+
uniform float numLayers;
|
|
959
|
+
uniform highp sampler2D colormap;
|
|
960
|
+
uniform lowp sampler3D blend3D;
|
|
961
|
+
uniform float opacity;
|
|
962
|
+
uniform vec3 xyzFrac;
|
|
963
|
+
uniform mat4 mtx;
|
|
964
|
+
void main(void) {
|
|
965
|
+
vec4 vx = vec4(TexCoord.x, TexCoord.y, coordZ, 1.0) * mtx;
|
|
966
|
+
uint idx = texture(intensityVol, vx.xyz).r;
|
|
967
|
+
FragColor = vec4(0.0, 0.0, 0.0, 0.0);
|
|
968
|
+
if (idx == uint(0))
|
|
969
|
+
return;
|
|
970
|
+
if (xyzFrac.x > 0.0) { //outline
|
|
971
|
+
vx = vec4(TexCoord.x+xyzFrac.x, TexCoord.y, coordZ, 1.0) * mtx;
|
|
972
|
+
uint R = texture(intensityVol, vx.xyz).r;
|
|
973
|
+
vx = vec4(TexCoord.x-xyzFrac.x, TexCoord.y, coordZ, 1.0) * mtx;
|
|
974
|
+
uint L = texture(intensityVol, vx.xyz).r;
|
|
975
|
+
vx = vec4(TexCoord.x, TexCoord.y+xyzFrac.y, coordZ, 1.0) * mtx;
|
|
976
|
+
uint A = texture(intensityVol, vx.xyz).r;
|
|
977
|
+
vx = vec4(TexCoord.x, TexCoord.y-xyzFrac.y, coordZ, 1.0) * mtx;
|
|
978
|
+
uint P = texture(intensityVol, vx.xyz).r;
|
|
979
|
+
vx = vec4(TexCoord.x, TexCoord.y, coordZ+xyzFrac.z, 1.0) * mtx;
|
|
980
|
+
uint S = texture(intensityVol, vx.xyz).r;
|
|
981
|
+
vx = vec4(TexCoord.x, TexCoord.y, coordZ-xyzFrac.z, 1.0) * mtx;
|
|
982
|
+
uint I = texture(intensityVol, vx.xyz).r;
|
|
983
|
+
if ((idx == R) && (idx == L) && (idx == A) && (idx == P) && (idx == S) && (idx == I))
|
|
984
|
+
return;
|
|
985
|
+
}
|
|
986
|
+
idx = ((idx - uint(1)) % uint(100))+uint(1);
|
|
987
|
+
float fx = (float(idx)+0.5) / 256.0;
|
|
988
|
+
float y = (2.0 * layer + 1.0)/(2.0 * numLayers);
|
|
989
|
+
FragColor = texture(colormap, vec2(fx, y)).rgba;
|
|
990
|
+
FragColor.a *= opacity;
|
|
991
|
+
if (layer < 2.0) return;
|
|
992
|
+
vec2 texXY = TexCoord.xy*0.5 +vec2(0.5,0.5);
|
|
993
|
+
vec4 prevColor = texture(blend3D, vec3(texXY, coordZ));
|
|
994
|
+
// https://en.wikipedia.org/wiki/Alpha_compositing
|
|
995
|
+
float aout = FragColor.a + (1.0 - FragColor.a) * prevColor.a;
|
|
996
|
+
if (aout <= 0.0) return;
|
|
997
|
+
FragColor.rgb = ((FragColor.rgb * FragColor.a) + (prevColor.rgb * prevColor.a * (1.0 - FragColor.a))) / aout;
|
|
998
|
+
FragColor.a = aout;
|
|
999
|
+
}`;
|
|
851
1000
|
var fragOrientShader = `#line 309
|
|
852
1001
|
precision highp int;
|
|
853
1002
|
precision highp float;
|
|
@@ -903,7 +1052,8 @@ uniform float opacity;
|
|
|
903
1052
|
uniform mat4 mtx;
|
|
904
1053
|
uniform bool hasAlpha;
|
|
905
1054
|
void main(void) {
|
|
906
|
-
|
|
1055
|
+
vec4 vx = vec4(TexCoord.xy, coordZ, 1.0) * mtx;
|
|
1056
|
+
uvec4 aColor = texture(intensityVol, vx.xyz);
|
|
907
1057
|
FragColor = vec4(float(aColor.r) / 255.0, float(aColor.g) / 255.0, float(aColor.b) / 255.0, float(aColor.a) / 255.0);
|
|
908
1058
|
if (!hasAlpha)
|
|
909
1059
|
FragColor.a = (FragColor.r * 0.21 + FragColor.g * 0.72 + FragColor.b * 0.07);
|
|
@@ -933,7 +1083,7 @@ var vertSurfaceShader = `#version 300 es
|
|
|
933
1083
|
layout(location=0) in vec3 pos;
|
|
934
1084
|
uniform mat4 mvpMtx;
|
|
935
1085
|
void main(void) {
|
|
936
|
-
gl_Position = mvpMtx * vec4(
|
|
1086
|
+
gl_Position = mvpMtx * vec4(pos, 1.0);
|
|
937
1087
|
}`;
|
|
938
1088
|
var fragSurfaceShader = `#version 300 es
|
|
939
1089
|
precision highp int;
|
|
@@ -943,38 +1093,18 @@ out vec4 color;
|
|
|
943
1093
|
void main() {
|
|
944
1094
|
color = surfaceColor;
|
|
945
1095
|
}`;
|
|
946
|
-
var vertDepthPickingShader = `#version 300 es
|
|
947
|
-
#line 414
|
|
948
|
-
layout(location=0) in vec3 pos;
|
|
949
|
-
in vec3 texCoords;
|
|
950
|
-
uniform mat4 mvpMtx;
|
|
951
|
-
out vec3 posColor;
|
|
952
|
-
void main(void) {
|
|
953
|
-
gl_Position = mvpMtx * vec4(pos, 1.0);
|
|
954
|
-
posColor = texCoords;
|
|
955
|
-
}`;
|
|
956
1096
|
var fragDepthPickingShader = `#version 300 es
|
|
957
1097
|
precision highp int;
|
|
958
1098
|
precision highp float;
|
|
959
1099
|
uniform int id;
|
|
960
|
-
in vec3
|
|
1100
|
+
in vec3 vColor;
|
|
961
1101
|
out vec4 color;
|
|
962
1102
|
void main() {
|
|
963
|
-
color = vec4(
|
|
964
|
-
}`;
|
|
965
|
-
var vertVolumePickingShader = `#version 300 es
|
|
966
|
-
#line 4
|
|
967
|
-
layout(location=0) in vec3 pos;
|
|
968
|
-
in vec3 texCoords;
|
|
969
|
-
uniform mat4 mvpMtx;
|
|
970
|
-
out vec3 posColor;
|
|
971
|
-
void main(void) {
|
|
972
|
-
gl_Position = mvpMtx * vec4(pos, 1.0);//mvpMtx * vec4(2.0 * (pos.xyz - 0.5), 1.0);
|
|
973
|
-
posColor = texCoords; //pos;
|
|
1103
|
+
color = vec4(vColor, float(id & 255) / 255.0);
|
|
974
1104
|
}`;
|
|
975
1105
|
var fragVolumePickingShader = `#version 300 es
|
|
976
|
-
#line
|
|
977
|
-
precision highp int;
|
|
1106
|
+
#line 506
|
|
1107
|
+
//precision highp int;
|
|
978
1108
|
precision highp float;
|
|
979
1109
|
uniform vec3 rayDir;
|
|
980
1110
|
uniform vec3 volScale;
|
|
@@ -982,92 +1112,57 @@ uniform vec3 texVox;
|
|
|
982
1112
|
uniform vec4 clipPlane;
|
|
983
1113
|
uniform highp sampler3D volume, overlay;
|
|
984
1114
|
uniform float overlays;
|
|
985
|
-
uniform float backOpacity;
|
|
986
1115
|
uniform int id;
|
|
987
|
-
in vec3
|
|
1116
|
+
in vec3 vColor;
|
|
988
1117
|
out vec4 fColor;
|
|
989
|
-
|
|
990
|
-
//texture space is 0..1 in each dimension, volScale adjusts for relative field of view
|
|
991
|
-
//convert startPosition to world space units:
|
|
992
|
-
vec3 startPosition = startPositionTex * volScale;
|
|
993
|
-
vec3 invR = 1.0 / rayDir;
|
|
994
|
-
vec3 tbot = invR * (vec3(0.0)-startPosition);
|
|
995
|
-
vec3 ttop = invR * (volScale-startPosition);
|
|
996
|
-
vec3 tmax = max(ttop, tbot);
|
|
997
|
-
vec2 t = min(tmax.xx, tmax.yz);
|
|
998
|
-
vec3 endPosition = startPosition + (rayDir * min(t.x, t.y));
|
|
999
|
-
//convert world position back to texture position:
|
|
1000
|
-
endPosition = endPosition / volScale;
|
|
1001
|
-
return endPosition;
|
|
1002
|
-
}
|
|
1003
|
-
vec4 applyClip (vec3 dir, inout vec4 samplePos, inout float len) {
|
|
1004
|
-
float cdot = dot(dir,clipPlane.xyz);
|
|
1005
|
-
if ((clipPlane.a > 1.0) || (cdot == 0.0)) return samplePos;
|
|
1006
|
-
bool frontface = (cdot > 0.0);
|
|
1007
|
-
float clipThick = 2.0;
|
|
1008
|
-
float dis = (-clipPlane.a - dot(clipPlane.xyz, samplePos.xyz-0.5)) / cdot;
|
|
1009
|
-
float disBackFace = (-(clipPlane.a-clipThick) - dot(clipPlane.xyz, samplePos.xyz-0.5)) / cdot;
|
|
1010
|
-
if (((frontface) && (dis >= len)) || ((!frontface) && (dis <= 0.0))) {
|
|
1011
|
-
samplePos.a = len + 1.0;
|
|
1012
|
-
return samplePos;
|
|
1013
|
-
}
|
|
1014
|
-
if (frontface) {
|
|
1015
|
-
dis = max(0.0, dis);
|
|
1016
|
-
samplePos = vec4(samplePos.xyz+dir * dis, dis);
|
|
1017
|
-
len = min(disBackFace, len);
|
|
1018
|
-
}
|
|
1019
|
-
if (!frontface) {
|
|
1020
|
-
len = min(dis, len);
|
|
1021
|
-
disBackFace = max(0.0, disBackFace);
|
|
1022
|
-
samplePos = vec4(samplePos.xyz+dir * disBackFace, disBackFace);
|
|
1023
|
-
}
|
|
1024
|
-
return samplePos;
|
|
1025
|
-
}
|
|
1118
|
+
` + kRenderFunc + `
|
|
1026
1119
|
void main() {
|
|
1027
|
-
vec3 start =
|
|
1120
|
+
vec3 start = vColor;
|
|
1121
|
+
fColor = vec4(0.0, 0.0, 0.0, 0.0); //assume no hit: ID = 0
|
|
1122
|
+
float fid = float(id & 255)/ 255.0;
|
|
1028
1123
|
vec3 backPosition = GetBackPosition(start);
|
|
1029
|
-
|
|
1030
|
-
|
|
1124
|
+
vec3 dir = backPosition - start;
|
|
1125
|
+
float len = length(dir);
|
|
1031
1126
|
float lenVox = length((texVox * start) - (texVox * backPosition));
|
|
1032
|
-
if (lenVox < 0.5) return;
|
|
1033
|
-
// fColor = vec4(posColor, 1.0);
|
|
1127
|
+
if ((lenVox < 0.5) || (len > 3.0)) return;//discard; //length limit for parallel rays
|
|
1034
1128
|
float sliceSize = len / lenVox; //e.g. if ray length is 1.0 and traverses 50 voxels, each voxel is 0.02 in unit cube
|
|
1035
1129
|
float stepSize = sliceSize; //quality: larger step is faster traversal, but fewer samples
|
|
1036
1130
|
float opacityCorrection = stepSize/sliceSize;
|
|
1037
|
-
|
|
1038
|
-
vec4 deltaDir = vec4(dir.xyz * stepSize, stepSize);
|
|
1131
|
+
dir = normalize(dir);
|
|
1039
1132
|
vec4 samplePos = vec4(start.xyz, 0.0); //ray position
|
|
1040
1133
|
float lenNoClip = len;
|
|
1041
|
-
|
|
1134
|
+
bool isClip = false;
|
|
1135
|
+
vec4 clipPos = applyClip(dir, samplePos, len, isClip);
|
|
1136
|
+
if (isClip) fColor = vec4(samplePos.xyz, 253.0 / 255.0); //assume no hit: ID = 0
|
|
1042
1137
|
//start: OPTIONAL fast pass: rapid traversal until first hit
|
|
1043
1138
|
float stepSizeFast = sliceSize * 1.9;
|
|
1044
1139
|
vec4 deltaDirFast = vec4(dir.xyz * stepSizeFast, stepSizeFast);
|
|
1045
1140
|
while (samplePos.a <= len) {
|
|
1046
1141
|
float val = texture(volume, samplePos.xyz).a;
|
|
1047
1142
|
if (val > 0.01) {
|
|
1048
|
-
fColor = vec4(samplePos.rgb,
|
|
1049
|
-
|
|
1143
|
+
fColor = vec4(samplePos.rgb, fid);
|
|
1144
|
+
break;
|
|
1050
1145
|
}
|
|
1051
1146
|
samplePos += deltaDirFast; //advance ray position
|
|
1052
1147
|
}
|
|
1053
1148
|
//end: fast pass
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1149
|
+
if (overlays < 1.0) {
|
|
1150
|
+
//if (fColor.a == 0.0) discard; //no hit, no overlays
|
|
1151
|
+
return; //background hit, no overlays
|
|
1152
|
+
}
|
|
1058
1153
|
//overlay pass
|
|
1059
|
-
len = lenNoClip;
|
|
1154
|
+
len = min(lenNoClip, samplePos.a); //only find overlay closer than background
|
|
1060
1155
|
samplePos = vec4(start.xyz, 0.0); //ray position
|
|
1061
|
-
//start: OPTIONAL fast pass: rapid traversal until first hit
|
|
1062
|
-
stepSizeFast = sliceSize * 1.9;
|
|
1063
|
-
deltaDirFast = vec4(dir.xyz * stepSizeFast, stepSizeFast);
|
|
1064
1156
|
while (samplePos.a <= len) {
|
|
1065
1157
|
float val = texture(overlay, samplePos.xyz).a;
|
|
1066
|
-
if (val > 0.01)
|
|
1158
|
+
if (val > 0.01) {
|
|
1159
|
+
fColor = vec4(samplePos.rgb, fid);
|
|
1160
|
+
return;
|
|
1161
|
+
}
|
|
1067
1162
|
samplePos += deltaDirFast; //advance ray position
|
|
1068
1163
|
}
|
|
1069
|
-
if (
|
|
1070
|
-
|
|
1164
|
+
//if (fColor.a == 0.0) discard; //no hit in either background or overlays
|
|
1165
|
+
//you only get here if there is a hit with the background that is closer than any overlay
|
|
1071
1166
|
}`;
|
|
1072
1167
|
const min$P = 0;
|
|
1073
1168
|
const max$P = 0;
|
|
@@ -5552,6 +5647,7 @@ var NiivueObject3D = function(id, vertexBuffer, mode, indexCount, indexBuffer =
|
|
|
5552
5647
|
this.renderShaders = [];
|
|
5553
5648
|
this.pickingShader = null;
|
|
5554
5649
|
this.isVisible = true;
|
|
5650
|
+
this.isPickable = true;
|
|
5555
5651
|
this.vertexBuffer = vertexBuffer;
|
|
5556
5652
|
this.indexCount = indexCount;
|
|
5557
5653
|
this.indexBuffer = indexBuffer;
|
|
@@ -5573,6 +5669,110 @@ var NiivueObject3D = function(id, vertexBuffer, mode, indexCount, indexBuffer =
|
|
|
5573
5669
|
this.extentsMin = [];
|
|
5574
5670
|
this.extentsMax = [];
|
|
5575
5671
|
};
|
|
5672
|
+
NiivueObject3D.generateCrosshairs = function(gl, id, xyzMM, xyzMin, xyzMax, radius, sides = 20) {
|
|
5673
|
+
let geometry = this.generateCrosshairsGeometry(gl, xyzMM, xyzMin, xyzMax, radius, sides);
|
|
5674
|
+
return new NiivueObject3D(id, geometry.vertexBuffer, gl.TRIANGLES, geometry.indexCount, geometry.indexBuffer);
|
|
5675
|
+
};
|
|
5676
|
+
NiivueObject3D.generateCrosshairsGeometry = function(gl, xyzMM, xyzMin, xyzMax, radius, sides = 20) {
|
|
5677
|
+
let vertices = [];
|
|
5678
|
+
let indices = [];
|
|
5679
|
+
let start = fromValues$1(xyzMin[0], xyzMM[1], xyzMM[2]);
|
|
5680
|
+
let dest = fromValues$1(xyzMax[0], xyzMM[1], xyzMM[2]);
|
|
5681
|
+
NiivueObject3D.makeCylinder(vertices, indices, start, dest, radius, sides);
|
|
5682
|
+
start = fromValues$1(xyzMM[0], xyzMin[1], xyzMM[2]);
|
|
5683
|
+
dest = fromValues$1(xyzMM[0], xyzMax[1], xyzMM[2]);
|
|
5684
|
+
NiivueObject3D.makeCylinder(vertices, indices, start, dest, radius, sides);
|
|
5685
|
+
start = fromValues$1(xyzMM[0], xyzMM[1], xyzMin[2]);
|
|
5686
|
+
dest = fromValues$1(xyzMM[0], xyzMM[1], xyzMax[2]);
|
|
5687
|
+
NiivueObject3D.makeCylinder(vertices, indices, start, dest, radius, sides);
|
|
5688
|
+
let vertexBuffer = gl.createBuffer();
|
|
5689
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
|
|
5690
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
|
|
5691
|
+
let indexBuffer = gl.createBuffer();
|
|
5692
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
|
|
5693
|
+
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
|
|
5694
|
+
return {
|
|
5695
|
+
vertexBuffer,
|
|
5696
|
+
indexBuffer,
|
|
5697
|
+
indexCount: indices.length
|
|
5698
|
+
};
|
|
5699
|
+
};
|
|
5700
|
+
NiivueObject3D.getFirstPerpVector = function(v1) {
|
|
5701
|
+
let v2 = fromValues$1(0, 0, 0);
|
|
5702
|
+
if (v1[0] === 0)
|
|
5703
|
+
v2[0] = 1;
|
|
5704
|
+
else if (v1[1] === 0)
|
|
5705
|
+
v2[1] = 1;
|
|
5706
|
+
else if (v1[2] === 0)
|
|
5707
|
+
v2[2] = 1;
|
|
5708
|
+
else {
|
|
5709
|
+
v2[0] = v1[2];
|
|
5710
|
+
v2[1] = v1[2];
|
|
5711
|
+
v2[2] = -(v1[0] + v1[1]);
|
|
5712
|
+
normalize(v2, v2);
|
|
5713
|
+
}
|
|
5714
|
+
return v2;
|
|
5715
|
+
};
|
|
5716
|
+
NiivueObject3D.makeCylinder = function(vertices, indices, start, dest, radius, sides = 20) {
|
|
5717
|
+
if (sides < 3)
|
|
5718
|
+
sides = 3;
|
|
5719
|
+
let v1 = create$1();
|
|
5720
|
+
subtract(v1, dest, start);
|
|
5721
|
+
normalize(v1, v1);
|
|
5722
|
+
let v2 = NiivueObject3D.getFirstPerpVector(v1);
|
|
5723
|
+
let v3 = create$1();
|
|
5724
|
+
cross(v3, v1, v2);
|
|
5725
|
+
normalize(v3, v3);
|
|
5726
|
+
let num_v = 2 * sides;
|
|
5727
|
+
let num_f = 2 * sides;
|
|
5728
|
+
{
|
|
5729
|
+
num_f += 2 * sides;
|
|
5730
|
+
num_v += 2;
|
|
5731
|
+
}
|
|
5732
|
+
let idx0 = Math.floor(vertices.length / 3);
|
|
5733
|
+
let idx = new Uint16Array(num_f * 3);
|
|
5734
|
+
let vtx = new Float32Array(num_v * 3);
|
|
5735
|
+
function setV(i, vec3) {
|
|
5736
|
+
vtx[i * 3 + 0] = vec3[0];
|
|
5737
|
+
vtx[i * 3 + 1] = vec3[1];
|
|
5738
|
+
vtx[i * 3 + 2] = vec3[2];
|
|
5739
|
+
}
|
|
5740
|
+
function setI(i, a, b, c) {
|
|
5741
|
+
idx[i * 3 + 0] = a + idx0;
|
|
5742
|
+
idx[i * 3 + 1] = b + idx0;
|
|
5743
|
+
idx[i * 3 + 2] = c + idx0;
|
|
5744
|
+
}
|
|
5745
|
+
let startPole = 2 * sides;
|
|
5746
|
+
let destPole = startPole + 1;
|
|
5747
|
+
{
|
|
5748
|
+
setV(startPole, start);
|
|
5749
|
+
setV(destPole, dest);
|
|
5750
|
+
}
|
|
5751
|
+
let pt1 = create$1();
|
|
5752
|
+
let pt2 = create$1();
|
|
5753
|
+
for (let i = 0; i < sides; i++) {
|
|
5754
|
+
let c = Math.cos(i / sides * 2 * Math.PI);
|
|
5755
|
+
let s = Math.sin(i / sides * 2 * Math.PI);
|
|
5756
|
+
pt1[0] = radius * (c * v2[0] + s * v3[0]);
|
|
5757
|
+
pt1[1] = radius * (c * v2[1] + s * v3[1]);
|
|
5758
|
+
pt1[2] = radius * (c * v2[2] + s * v3[2]);
|
|
5759
|
+
add$1(pt2, start, pt1);
|
|
5760
|
+
setV(i, pt2);
|
|
5761
|
+
add$1(pt2, dest, pt1);
|
|
5762
|
+
setV(i + sides, pt2);
|
|
5763
|
+
let nxt = 0;
|
|
5764
|
+
if (i < sides - 1)
|
|
5765
|
+
nxt = i + 1;
|
|
5766
|
+
setI(i * 2, i, nxt, i + sides);
|
|
5767
|
+
setI(i * 2 + 1, nxt, nxt + sides, i + sides);
|
|
5768
|
+
{
|
|
5769
|
+
setI(sides * 2 + i, i, startPole, nxt);
|
|
5770
|
+
setI(sides * 2 + i + sides, destPole, i + sides, nxt + sides);
|
|
5771
|
+
}
|
|
5772
|
+
}
|
|
5773
|
+
indices.push(...idx);
|
|
5774
|
+
vertices.push(...vtx);
|
|
5775
|
+
};
|
|
5576
5776
|
var NiivueShader3D = function(shader) {
|
|
5577
5777
|
this.shader = shader;
|
|
5578
5778
|
this.uniforms = shader.uniforms;
|
|
@@ -6377,9 +6577,9 @@ const Z_BINARY = 0;
|
|
|
6377
6577
|
const Z_TEXT = 1;
|
|
6378
6578
|
const Z_UNKNOWN$1 = 2;
|
|
6379
6579
|
function zero$1(buf) {
|
|
6380
|
-
let
|
|
6381
|
-
while (--
|
|
6382
|
-
buf[
|
|
6580
|
+
let len2 = buf.length;
|
|
6581
|
+
while (--len2 >= 0) {
|
|
6582
|
+
buf[len2] = 0;
|
|
6383
6583
|
}
|
|
6384
6584
|
}
|
|
6385
6585
|
const STORED_BLOCK = 0;
|
|
@@ -6440,27 +6640,27 @@ const put_short = (s, w) => {
|
|
|
6440
6640
|
s.pending_buf[s.pending++] = w & 255;
|
|
6441
6641
|
s.pending_buf[s.pending++] = w >>> 8 & 255;
|
|
6442
6642
|
};
|
|
6443
|
-
const send_bits = (s, value,
|
|
6444
|
-
if (s.bi_valid > Buf_size -
|
|
6643
|
+
const send_bits = (s, value, length2) => {
|
|
6644
|
+
if (s.bi_valid > Buf_size - length2) {
|
|
6445
6645
|
s.bi_buf |= value << s.bi_valid & 65535;
|
|
6446
6646
|
put_short(s, s.bi_buf);
|
|
6447
6647
|
s.bi_buf = value >> Buf_size - s.bi_valid;
|
|
6448
|
-
s.bi_valid +=
|
|
6648
|
+
s.bi_valid += length2 - Buf_size;
|
|
6449
6649
|
} else {
|
|
6450
6650
|
s.bi_buf |= value << s.bi_valid & 65535;
|
|
6451
|
-
s.bi_valid +=
|
|
6651
|
+
s.bi_valid += length2;
|
|
6452
6652
|
}
|
|
6453
6653
|
};
|
|
6454
6654
|
const send_code = (s, c, tree) => {
|
|
6455
6655
|
send_bits(s, tree[c * 2], tree[c * 2 + 1]);
|
|
6456
6656
|
};
|
|
6457
|
-
const bi_reverse = (code,
|
|
6657
|
+
const bi_reverse = (code, len2) => {
|
|
6458
6658
|
let res = 0;
|
|
6459
6659
|
do {
|
|
6460
6660
|
res |= code & 1;
|
|
6461
6661
|
code >>>= 1;
|
|
6462
6662
|
res <<= 1;
|
|
6463
|
-
} while (--
|
|
6663
|
+
} while (--len2 > 0);
|
|
6464
6664
|
return res >>> 1;
|
|
6465
6665
|
};
|
|
6466
6666
|
const bi_flush = (s) => {
|
|
@@ -6551,28 +6751,28 @@ const gen_codes = (tree, max_code, bl_count) => {
|
|
|
6551
6751
|
next_code[bits] = code = code + bl_count[bits - 1] << 1;
|
|
6552
6752
|
}
|
|
6553
6753
|
for (n = 0; n <= max_code; n++) {
|
|
6554
|
-
let
|
|
6555
|
-
if (
|
|
6754
|
+
let len2 = tree[n * 2 + 1];
|
|
6755
|
+
if (len2 === 0) {
|
|
6556
6756
|
continue;
|
|
6557
6757
|
}
|
|
6558
|
-
tree[n * 2] = bi_reverse(next_code[
|
|
6758
|
+
tree[n * 2] = bi_reverse(next_code[len2]++, len2);
|
|
6559
6759
|
}
|
|
6560
6760
|
};
|
|
6561
6761
|
const tr_static_init = () => {
|
|
6562
6762
|
let n;
|
|
6563
6763
|
let bits;
|
|
6564
|
-
let
|
|
6764
|
+
let length2;
|
|
6565
6765
|
let code;
|
|
6566
6766
|
let dist;
|
|
6567
6767
|
const bl_count = new Array(MAX_BITS$1 + 1);
|
|
6568
|
-
|
|
6768
|
+
length2 = 0;
|
|
6569
6769
|
for (code = 0; code < LENGTH_CODES$1 - 1; code++) {
|
|
6570
|
-
base_length[code] =
|
|
6770
|
+
base_length[code] = length2;
|
|
6571
6771
|
for (n = 0; n < 1 << extra_lbits[code]; n++) {
|
|
6572
|
-
_length_code[
|
|
6772
|
+
_length_code[length2++] = code;
|
|
6573
6773
|
}
|
|
6574
6774
|
}
|
|
6575
|
-
_length_code[
|
|
6775
|
+
_length_code[length2 - 1] = code;
|
|
6576
6776
|
dist = 0;
|
|
6577
6777
|
for (code = 0; code < 16; code++) {
|
|
6578
6778
|
base_dist[code] = dist;
|
|
@@ -6644,14 +6844,14 @@ const bi_windup = (s) => {
|
|
|
6644
6844
|
s.bi_buf = 0;
|
|
6645
6845
|
s.bi_valid = 0;
|
|
6646
6846
|
};
|
|
6647
|
-
const copy_block = (s, buf,
|
|
6847
|
+
const copy_block = (s, buf, len2, header) => {
|
|
6648
6848
|
bi_windup(s);
|
|
6649
6849
|
if (header) {
|
|
6650
|
-
put_short(s,
|
|
6651
|
-
put_short(s, ~
|
|
6850
|
+
put_short(s, len2);
|
|
6851
|
+
put_short(s, ~len2);
|
|
6652
6852
|
}
|
|
6653
|
-
s.pending_buf.set(s.window.subarray(buf, buf +
|
|
6654
|
-
s.pending +=
|
|
6853
|
+
s.pending_buf.set(s.window.subarray(buf, buf + len2), s.pending);
|
|
6854
|
+
s.pending += len2;
|
|
6655
6855
|
};
|
|
6656
6856
|
const smaller = (tree, n, m, depth) => {
|
|
6657
6857
|
const _n2 = n * 2;
|
|
@@ -6967,11 +7167,11 @@ trees._tr_stored_block = _tr_stored_block$1;
|
|
|
6967
7167
|
trees._tr_flush_block = _tr_flush_block$1;
|
|
6968
7168
|
trees._tr_tally = _tr_tally$1;
|
|
6969
7169
|
trees._tr_align = _tr_align$1;
|
|
6970
|
-
const adler32$2 = (adler, buf,
|
|
7170
|
+
const adler32$2 = (adler, buf, len2, pos) => {
|
|
6971
7171
|
let s1 = adler & 65535 | 0, s2 = adler >>> 16 & 65535 | 0, n = 0;
|
|
6972
|
-
while (
|
|
6973
|
-
n =
|
|
6974
|
-
|
|
7172
|
+
while (len2 !== 0) {
|
|
7173
|
+
n = len2 > 2e3 ? 2e3 : len2;
|
|
7174
|
+
len2 -= n;
|
|
6975
7175
|
do {
|
|
6976
7176
|
s1 = s1 + buf[pos++] | 0;
|
|
6977
7177
|
s2 = s2 + s1 | 0;
|
|
@@ -6994,9 +7194,9 @@ const makeTable = () => {
|
|
|
6994
7194
|
return table;
|
|
6995
7195
|
};
|
|
6996
7196
|
const crcTable = new Uint32Array(makeTable());
|
|
6997
|
-
const crc32$2 = (crc, buf,
|
|
7197
|
+
const crc32$2 = (crc, buf, len2, pos) => {
|
|
6998
7198
|
const t = crcTable;
|
|
6999
|
-
const end = pos +
|
|
7199
|
+
const end = pos + len2;
|
|
7000
7200
|
crc ^= -1;
|
|
7001
7201
|
for (let i = pos; i < end; i++) {
|
|
7002
7202
|
crc = crc >>> 8 ^ t[(crc ^ buf[i]) & 255];
|
|
@@ -7103,28 +7303,28 @@ const rank = (f) => {
|
|
|
7103
7303
|
return (f << 1) - (f > 4 ? 9 : 0);
|
|
7104
7304
|
};
|
|
7105
7305
|
const zero = (buf) => {
|
|
7106
|
-
let
|
|
7107
|
-
while (--
|
|
7108
|
-
buf[
|
|
7306
|
+
let len2 = buf.length;
|
|
7307
|
+
while (--len2 >= 0) {
|
|
7308
|
+
buf[len2] = 0;
|
|
7109
7309
|
}
|
|
7110
7310
|
};
|
|
7111
7311
|
let HASH_ZLIB = (s, prev, data) => (prev << s.hash_shift ^ data) & s.hash_mask;
|
|
7112
7312
|
let HASH = HASH_ZLIB;
|
|
7113
7313
|
const flush_pending = (strm) => {
|
|
7114
7314
|
const s = strm.state;
|
|
7115
|
-
let
|
|
7116
|
-
if (
|
|
7117
|
-
|
|
7315
|
+
let len2 = s.pending;
|
|
7316
|
+
if (len2 > strm.avail_out) {
|
|
7317
|
+
len2 = strm.avail_out;
|
|
7118
7318
|
}
|
|
7119
|
-
if (
|
|
7319
|
+
if (len2 === 0) {
|
|
7120
7320
|
return;
|
|
7121
7321
|
}
|
|
7122
|
-
strm.output.set(s.pending_buf.subarray(s.pending_out, s.pending_out +
|
|
7123
|
-
strm.next_out +=
|
|
7124
|
-
s.pending_out +=
|
|
7125
|
-
strm.total_out +=
|
|
7126
|
-
strm.avail_out -=
|
|
7127
|
-
s.pending -=
|
|
7322
|
+
strm.output.set(s.pending_buf.subarray(s.pending_out, s.pending_out + len2), strm.next_out);
|
|
7323
|
+
strm.next_out += len2;
|
|
7324
|
+
s.pending_out += len2;
|
|
7325
|
+
strm.total_out += len2;
|
|
7326
|
+
strm.avail_out -= len2;
|
|
7327
|
+
s.pending -= len2;
|
|
7128
7328
|
if (s.pending === 0) {
|
|
7129
7329
|
s.pending_out = 0;
|
|
7130
7330
|
}
|
|
@@ -7142,29 +7342,29 @@ const putShortMSB = (s, b) => {
|
|
|
7142
7342
|
s.pending_buf[s.pending++] = b & 255;
|
|
7143
7343
|
};
|
|
7144
7344
|
const read_buf = (strm, buf, start, size) => {
|
|
7145
|
-
let
|
|
7146
|
-
if (
|
|
7147
|
-
|
|
7345
|
+
let len2 = strm.avail_in;
|
|
7346
|
+
if (len2 > size) {
|
|
7347
|
+
len2 = size;
|
|
7148
7348
|
}
|
|
7149
|
-
if (
|
|
7349
|
+
if (len2 === 0) {
|
|
7150
7350
|
return 0;
|
|
7151
7351
|
}
|
|
7152
|
-
strm.avail_in -=
|
|
7153
|
-
buf.set(strm.input.subarray(strm.next_in, strm.next_in +
|
|
7352
|
+
strm.avail_in -= len2;
|
|
7353
|
+
buf.set(strm.input.subarray(strm.next_in, strm.next_in + len2), start);
|
|
7154
7354
|
if (strm.state.wrap === 1) {
|
|
7155
|
-
strm.adler = adler32$1(strm.adler, buf,
|
|
7355
|
+
strm.adler = adler32$1(strm.adler, buf, len2, start);
|
|
7156
7356
|
} else if (strm.state.wrap === 2) {
|
|
7157
|
-
strm.adler = crc32$1(strm.adler, buf,
|
|
7357
|
+
strm.adler = crc32$1(strm.adler, buf, len2, start);
|
|
7158
7358
|
}
|
|
7159
|
-
strm.next_in +=
|
|
7160
|
-
strm.total_in +=
|
|
7161
|
-
return
|
|
7359
|
+
strm.next_in += len2;
|
|
7360
|
+
strm.total_in += len2;
|
|
7361
|
+
return len2;
|
|
7162
7362
|
};
|
|
7163
7363
|
const longest_match = (s, cur_match) => {
|
|
7164
7364
|
let chain_length = s.max_chain_length;
|
|
7165
7365
|
let scan = s.strstart;
|
|
7166
7366
|
let match;
|
|
7167
|
-
let
|
|
7367
|
+
let len2;
|
|
7168
7368
|
let best_len = s.prev_length;
|
|
7169
7369
|
let nice_match = s.nice_match;
|
|
7170
7370
|
const limit = s.strstart > s.w_size - MIN_LOOKAHEAD ? s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0;
|
|
@@ -7189,12 +7389,12 @@ const longest_match = (s, cur_match) => {
|
|
|
7189
7389
|
match++;
|
|
7190
7390
|
do {
|
|
7191
7391
|
} while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && scan < strend);
|
|
7192
|
-
|
|
7392
|
+
len2 = MAX_MATCH - (strend - scan);
|
|
7193
7393
|
scan = strend - MAX_MATCH;
|
|
7194
|
-
if (
|
|
7394
|
+
if (len2 > best_len) {
|
|
7195
7395
|
s.match_start = cur_match;
|
|
7196
|
-
best_len =
|
|
7197
|
-
if (
|
|
7396
|
+
best_len = len2;
|
|
7397
|
+
if (len2 >= nice_match) {
|
|
7198
7398
|
break;
|
|
7199
7399
|
}
|
|
7200
7400
|
scan_end1 = _win[scan + best_len - 1];
|
|
@@ -8088,11 +8288,11 @@ common.assign = function(obj) {
|
|
|
8088
8288
|
return obj;
|
|
8089
8289
|
};
|
|
8090
8290
|
common.flattenChunks = (chunks) => {
|
|
8091
|
-
let
|
|
8291
|
+
let len2 = 0;
|
|
8092
8292
|
for (let i = 0, l = chunks.length; i < l; i++) {
|
|
8093
|
-
|
|
8293
|
+
len2 += chunks[i].length;
|
|
8094
8294
|
}
|
|
8095
|
-
const result = new Uint8Array(
|
|
8295
|
+
const result = new Uint8Array(len2);
|
|
8096
8296
|
for (let i = 0, pos = 0, l = chunks.length; i < l; i++) {
|
|
8097
8297
|
let chunk = chunks[i];
|
|
8098
8298
|
result.set(chunk, pos);
|
|
@@ -8156,26 +8356,26 @@ strings$2.string2buf = (str) => {
|
|
|
8156
8356
|
}
|
|
8157
8357
|
return buf;
|
|
8158
8358
|
};
|
|
8159
|
-
const buf2binstring = (buf,
|
|
8160
|
-
if (
|
|
8359
|
+
const buf2binstring = (buf, len2) => {
|
|
8360
|
+
if (len2 < 65534) {
|
|
8161
8361
|
if (buf.subarray && STR_APPLY_UIA_OK) {
|
|
8162
|
-
return String.fromCharCode.apply(null, buf.length ===
|
|
8362
|
+
return String.fromCharCode.apply(null, buf.length === len2 ? buf : buf.subarray(0, len2));
|
|
8163
8363
|
}
|
|
8164
8364
|
}
|
|
8165
8365
|
let result = "";
|
|
8166
|
-
for (let i = 0; i <
|
|
8366
|
+
for (let i = 0; i < len2; i++) {
|
|
8167
8367
|
result += String.fromCharCode(buf[i]);
|
|
8168
8368
|
}
|
|
8169
8369
|
return result;
|
|
8170
8370
|
};
|
|
8171
8371
|
strings$2.buf2string = (buf, max2) => {
|
|
8172
|
-
const
|
|
8372
|
+
const len2 = max2 || buf.length;
|
|
8173
8373
|
if (typeof TextDecoder === "function" && TextDecoder.prototype.decode) {
|
|
8174
8374
|
return new TextDecoder().decode(buf.subarray(0, max2));
|
|
8175
8375
|
}
|
|
8176
8376
|
let i, out;
|
|
8177
|
-
const utf16buf = new Array(
|
|
8178
|
-
for (out = 0, i = 0; i <
|
|
8377
|
+
const utf16buf = new Array(len2 * 2);
|
|
8378
|
+
for (out = 0, i = 0; i < len2; ) {
|
|
8179
8379
|
let c = buf[i++];
|
|
8180
8380
|
if (c < 128) {
|
|
8181
8381
|
utf16buf[out++] = c;
|
|
@@ -8188,7 +8388,7 @@ strings$2.buf2string = (buf, max2) => {
|
|
|
8188
8388
|
continue;
|
|
8189
8389
|
}
|
|
8190
8390
|
c &= c_len === 2 ? 31 : c_len === 3 ? 15 : 7;
|
|
8191
|
-
while (c_len > 1 && i <
|
|
8391
|
+
while (c_len > 1 && i < len2) {
|
|
8192
8392
|
c = c << 6 | buf[i++] & 63;
|
|
8193
8393
|
c_len--;
|
|
8194
8394
|
}
|
|
@@ -8411,7 +8611,7 @@ var inffast = function inflate_fast(strm, start) {
|
|
|
8411
8611
|
let dmask;
|
|
8412
8612
|
let here;
|
|
8413
8613
|
let op;
|
|
8414
|
-
let
|
|
8614
|
+
let len2;
|
|
8415
8615
|
let dist;
|
|
8416
8616
|
let from;
|
|
8417
8617
|
let from_source;
|
|
@@ -8453,14 +8653,14 @@ var inffast = function inflate_fast(strm, start) {
|
|
|
8453
8653
|
if (op === 0) {
|
|
8454
8654
|
output[_out++] = here & 65535;
|
|
8455
8655
|
} else if (op & 16) {
|
|
8456
|
-
|
|
8656
|
+
len2 = here & 65535;
|
|
8457
8657
|
op &= 15;
|
|
8458
8658
|
if (op) {
|
|
8459
8659
|
if (bits < op) {
|
|
8460
8660
|
hold += input[_in++] << bits;
|
|
8461
8661
|
bits += 8;
|
|
8462
8662
|
}
|
|
8463
|
-
|
|
8663
|
+
len2 += hold & (1 << op) - 1;
|
|
8464
8664
|
hold >>>= op;
|
|
8465
8665
|
bits -= op;
|
|
8466
8666
|
}
|
|
@@ -8510,8 +8710,8 @@ var inffast = function inflate_fast(strm, start) {
|
|
|
8510
8710
|
from_source = s_window;
|
|
8511
8711
|
if (wnext === 0) {
|
|
8512
8712
|
from += wsize - op;
|
|
8513
|
-
if (op <
|
|
8514
|
-
|
|
8713
|
+
if (op < len2) {
|
|
8714
|
+
len2 -= op;
|
|
8515
8715
|
do {
|
|
8516
8716
|
output[_out++] = s_window[from++];
|
|
8517
8717
|
} while (--op);
|
|
@@ -8521,15 +8721,15 @@ var inffast = function inflate_fast(strm, start) {
|
|
|
8521
8721
|
} else if (wnext < op) {
|
|
8522
8722
|
from += wsize + wnext - op;
|
|
8523
8723
|
op -= wnext;
|
|
8524
|
-
if (op <
|
|
8525
|
-
|
|
8724
|
+
if (op < len2) {
|
|
8725
|
+
len2 -= op;
|
|
8526
8726
|
do {
|
|
8527
8727
|
output[_out++] = s_window[from++];
|
|
8528
8728
|
} while (--op);
|
|
8529
8729
|
from = 0;
|
|
8530
|
-
if (wnext <
|
|
8730
|
+
if (wnext < len2) {
|
|
8531
8731
|
op = wnext;
|
|
8532
|
-
|
|
8732
|
+
len2 -= op;
|
|
8533
8733
|
do {
|
|
8534
8734
|
output[_out++] = s_window[from++];
|
|
8535
8735
|
} while (--op);
|
|
@@ -8539,8 +8739,8 @@ var inffast = function inflate_fast(strm, start) {
|
|
|
8539
8739
|
}
|
|
8540
8740
|
} else {
|
|
8541
8741
|
from += wnext - op;
|
|
8542
|
-
if (op <
|
|
8543
|
-
|
|
8742
|
+
if (op < len2) {
|
|
8743
|
+
len2 -= op;
|
|
8544
8744
|
do {
|
|
8545
8745
|
output[_out++] = s_window[from++];
|
|
8546
8746
|
} while (--op);
|
|
@@ -8548,15 +8748,15 @@ var inffast = function inflate_fast(strm, start) {
|
|
|
8548
8748
|
from_source = output;
|
|
8549
8749
|
}
|
|
8550
8750
|
}
|
|
8551
|
-
while (
|
|
8751
|
+
while (len2 > 2) {
|
|
8552
8752
|
output[_out++] = from_source[from++];
|
|
8553
8753
|
output[_out++] = from_source[from++];
|
|
8554
8754
|
output[_out++] = from_source[from++];
|
|
8555
|
-
|
|
8755
|
+
len2 -= 3;
|
|
8556
8756
|
}
|
|
8557
|
-
if (
|
|
8757
|
+
if (len2) {
|
|
8558
8758
|
output[_out++] = from_source[from++];
|
|
8559
|
-
if (
|
|
8759
|
+
if (len2 > 1) {
|
|
8560
8760
|
output[_out++] = from_source[from++];
|
|
8561
8761
|
}
|
|
8562
8762
|
}
|
|
@@ -8566,11 +8766,11 @@ var inffast = function inflate_fast(strm, start) {
|
|
|
8566
8766
|
output[_out++] = output[from++];
|
|
8567
8767
|
output[_out++] = output[from++];
|
|
8568
8768
|
output[_out++] = output[from++];
|
|
8569
|
-
|
|
8570
|
-
} while (
|
|
8571
|
-
if (
|
|
8769
|
+
len2 -= 3;
|
|
8770
|
+
} while (len2 > 2);
|
|
8771
|
+
if (len2) {
|
|
8572
8772
|
output[_out++] = output[from++];
|
|
8573
|
-
if (
|
|
8773
|
+
if (len2 > 1) {
|
|
8574
8774
|
output[_out++] = output[from++];
|
|
8575
8775
|
}
|
|
8576
8776
|
}
|
|
@@ -8599,9 +8799,9 @@ var inffast = function inflate_fast(strm, start) {
|
|
|
8599
8799
|
break;
|
|
8600
8800
|
}
|
|
8601
8801
|
} while (_in < last && _out < end);
|
|
8602
|
-
|
|
8603
|
-
_in -=
|
|
8604
|
-
bits -=
|
|
8802
|
+
len2 = bits >> 3;
|
|
8803
|
+
_in -= len2;
|
|
8804
|
+
bits -= len2 << 3;
|
|
8605
8805
|
hold &= (1 << bits) - 1;
|
|
8606
8806
|
strm.next_in = _in;
|
|
8607
8807
|
strm.next_out = _out;
|
|
@@ -8753,7 +8953,7 @@ const dext = new Uint8Array([
|
|
|
8753
8953
|
]);
|
|
8754
8954
|
const inflate_table$1 = (type, lens, lens_index, codes, table, table_index, work, opts) => {
|
|
8755
8955
|
const bits = opts.bits;
|
|
8756
|
-
let
|
|
8956
|
+
let len2 = 0;
|
|
8757
8957
|
let sym = 0;
|
|
8758
8958
|
let min2 = 0, max2 = 0;
|
|
8759
8959
|
let root = 0;
|
|
@@ -8775,8 +8975,8 @@ const inflate_table$1 = (type, lens, lens_index, codes, table, table_index, work
|
|
|
8775
8975
|
let extra = null;
|
|
8776
8976
|
let extra_index = 0;
|
|
8777
8977
|
let here_bits, here_op, here_val;
|
|
8778
|
-
for (
|
|
8779
|
-
count[
|
|
8978
|
+
for (len2 = 0; len2 <= MAXBITS; len2++) {
|
|
8979
|
+
count[len2] = 0;
|
|
8780
8980
|
}
|
|
8781
8981
|
for (sym = 0; sym < codes; sym++) {
|
|
8782
8982
|
count[lens[lens_index + sym]]++;
|
|
@@ -8805,9 +9005,9 @@ const inflate_table$1 = (type, lens, lens_index, codes, table, table_index, work
|
|
|
8805
9005
|
root = min2;
|
|
8806
9006
|
}
|
|
8807
9007
|
left = 1;
|
|
8808
|
-
for (
|
|
9008
|
+
for (len2 = 1; len2 <= MAXBITS; len2++) {
|
|
8809
9009
|
left <<= 1;
|
|
8810
|
-
left -= count[
|
|
9010
|
+
left -= count[len2];
|
|
8811
9011
|
if (left < 0) {
|
|
8812
9012
|
return -1;
|
|
8813
9013
|
}
|
|
@@ -8816,8 +9016,8 @@ const inflate_table$1 = (type, lens, lens_index, codes, table, table_index, work
|
|
|
8816
9016
|
return -1;
|
|
8817
9017
|
}
|
|
8818
9018
|
offs[1] = 0;
|
|
8819
|
-
for (
|
|
8820
|
-
offs[
|
|
9019
|
+
for (len2 = 1; len2 < MAXBITS; len2++) {
|
|
9020
|
+
offs[len2 + 1] = offs[len2] + count[len2];
|
|
8821
9021
|
}
|
|
8822
9022
|
for (sym = 0; sym < codes; sym++) {
|
|
8823
9023
|
if (lens[lens_index + sym] !== 0) {
|
|
@@ -8840,7 +9040,7 @@ const inflate_table$1 = (type, lens, lens_index, codes, table, table_index, work
|
|
|
8840
9040
|
}
|
|
8841
9041
|
huff = 0;
|
|
8842
9042
|
sym = 0;
|
|
8843
|
-
|
|
9043
|
+
len2 = min2;
|
|
8844
9044
|
next = table_index;
|
|
8845
9045
|
curr = root;
|
|
8846
9046
|
drop = 0;
|
|
@@ -8851,7 +9051,7 @@ const inflate_table$1 = (type, lens, lens_index, codes, table, table_index, work
|
|
|
8851
9051
|
return 1;
|
|
8852
9052
|
}
|
|
8853
9053
|
for (; ; ) {
|
|
8854
|
-
here_bits =
|
|
9054
|
+
here_bits = len2 - drop;
|
|
8855
9055
|
if (work[sym] < end) {
|
|
8856
9056
|
here_op = 0;
|
|
8857
9057
|
here_val = work[sym];
|
|
@@ -8862,14 +9062,14 @@ const inflate_table$1 = (type, lens, lens_index, codes, table, table_index, work
|
|
|
8862
9062
|
here_op = 32 + 64;
|
|
8863
9063
|
here_val = 0;
|
|
8864
9064
|
}
|
|
8865
|
-
incr = 1 <<
|
|
9065
|
+
incr = 1 << len2 - drop;
|
|
8866
9066
|
fill = 1 << curr;
|
|
8867
9067
|
min2 = fill;
|
|
8868
9068
|
do {
|
|
8869
9069
|
fill -= incr;
|
|
8870
9070
|
table[next + (huff >> drop) + fill] = here_bits << 24 | here_op << 16 | here_val | 0;
|
|
8871
9071
|
} while (fill !== 0);
|
|
8872
|
-
incr = 1 <<
|
|
9072
|
+
incr = 1 << len2 - 1;
|
|
8873
9073
|
while (huff & incr) {
|
|
8874
9074
|
incr >>= 1;
|
|
8875
9075
|
}
|
|
@@ -8880,18 +9080,18 @@ const inflate_table$1 = (type, lens, lens_index, codes, table, table_index, work
|
|
|
8880
9080
|
huff = 0;
|
|
8881
9081
|
}
|
|
8882
9082
|
sym++;
|
|
8883
|
-
if (--count[
|
|
8884
|
-
if (
|
|
9083
|
+
if (--count[len2] === 0) {
|
|
9084
|
+
if (len2 === max2) {
|
|
8885
9085
|
break;
|
|
8886
9086
|
}
|
|
8887
|
-
|
|
9087
|
+
len2 = lens[lens_index + work[sym]];
|
|
8888
9088
|
}
|
|
8889
|
-
if (
|
|
9089
|
+
if (len2 > root && (huff & mask) !== low) {
|
|
8890
9090
|
if (drop === 0) {
|
|
8891
9091
|
drop = root;
|
|
8892
9092
|
}
|
|
8893
9093
|
next += min2;
|
|
8894
|
-
curr =
|
|
9094
|
+
curr = len2 - drop;
|
|
8895
9095
|
left = 1 << curr;
|
|
8896
9096
|
while (curr + drop < max2) {
|
|
8897
9097
|
left -= count[curr + drop];
|
|
@@ -8910,7 +9110,7 @@ const inflate_table$1 = (type, lens, lens_index, codes, table, table_index, work
|
|
|
8910
9110
|
}
|
|
8911
9111
|
}
|
|
8912
9112
|
if (huff !== 0) {
|
|
8913
|
-
table[next + huff] =
|
|
9113
|
+
table[next + huff] = len2 - drop << 24 | 64 << 16 | 0;
|
|
8914
9114
|
}
|
|
8915
9115
|
opts.bits = root;
|
|
8916
9116
|
return 0;
|
|
@@ -9169,7 +9369,7 @@ const inflate$2 = (strm, flush) => {
|
|
|
9169
9369
|
let here = 0;
|
|
9170
9370
|
let here_bits, here_op, here_val;
|
|
9171
9371
|
let last_bits, last_op, last_val;
|
|
9172
|
-
let
|
|
9372
|
+
let len2;
|
|
9173
9373
|
let ret;
|
|
9174
9374
|
const hbuf = new Uint8Array(4);
|
|
9175
9375
|
let opts;
|
|
@@ -9235,10 +9435,10 @@ const inflate$2 = (strm, flush) => {
|
|
|
9235
9435
|
}
|
|
9236
9436
|
hold >>>= 4;
|
|
9237
9437
|
bits -= 4;
|
|
9238
|
-
|
|
9438
|
+
len2 = (hold & 15) + 8;
|
|
9239
9439
|
if (state.wbits === 0) {
|
|
9240
|
-
state.wbits =
|
|
9241
|
-
} else if (
|
|
9440
|
+
state.wbits = len2;
|
|
9441
|
+
} else if (len2 > state.wbits) {
|
|
9242
9442
|
strm.msg = "invalid window size";
|
|
9243
9443
|
state.mode = BAD;
|
|
9244
9444
|
break;
|
|
@@ -9356,11 +9556,11 @@ const inflate$2 = (strm, flush) => {
|
|
|
9356
9556
|
}
|
|
9357
9557
|
if (copy2) {
|
|
9358
9558
|
if (state.head) {
|
|
9359
|
-
|
|
9559
|
+
len2 = state.head.extra_len - state.length;
|
|
9360
9560
|
if (!state.head.extra) {
|
|
9361
9561
|
state.head.extra = new Uint8Array(state.head.extra_len);
|
|
9362
9562
|
}
|
|
9363
|
-
state.head.extra.set(input.subarray(next, next + copy2),
|
|
9563
|
+
state.head.extra.set(input.subarray(next, next + copy2), len2);
|
|
9364
9564
|
}
|
|
9365
9565
|
if (state.flags & 512) {
|
|
9366
9566
|
state.check = crc32(state.check, input, copy2, next);
|
|
@@ -9382,17 +9582,17 @@ const inflate$2 = (strm, flush) => {
|
|
|
9382
9582
|
}
|
|
9383
9583
|
copy2 = 0;
|
|
9384
9584
|
do {
|
|
9385
|
-
|
|
9386
|
-
if (state.head &&
|
|
9387
|
-
state.head.name += String.fromCharCode(
|
|
9585
|
+
len2 = input[next + copy2++];
|
|
9586
|
+
if (state.head && len2 && state.length < 65536) {
|
|
9587
|
+
state.head.name += String.fromCharCode(len2);
|
|
9388
9588
|
}
|
|
9389
|
-
} while (
|
|
9589
|
+
} while (len2 && copy2 < have);
|
|
9390
9590
|
if (state.flags & 512) {
|
|
9391
9591
|
state.check = crc32(state.check, input, copy2, next);
|
|
9392
9592
|
}
|
|
9393
9593
|
have -= copy2;
|
|
9394
9594
|
next += copy2;
|
|
9395
|
-
if (
|
|
9595
|
+
if (len2) {
|
|
9396
9596
|
break inf_leave;
|
|
9397
9597
|
}
|
|
9398
9598
|
} else if (state.head) {
|
|
@@ -9407,17 +9607,17 @@ const inflate$2 = (strm, flush) => {
|
|
|
9407
9607
|
}
|
|
9408
9608
|
copy2 = 0;
|
|
9409
9609
|
do {
|
|
9410
|
-
|
|
9411
|
-
if (state.head &&
|
|
9412
|
-
state.head.comment += String.fromCharCode(
|
|
9610
|
+
len2 = input[next + copy2++];
|
|
9611
|
+
if (state.head && len2 && state.length < 65536) {
|
|
9612
|
+
state.head.comment += String.fromCharCode(len2);
|
|
9413
9613
|
}
|
|
9414
|
-
} while (
|
|
9614
|
+
} while (len2 && copy2 < have);
|
|
9415
9615
|
if (state.flags & 512) {
|
|
9416
9616
|
state.check = crc32(state.check, input, copy2, next);
|
|
9417
9617
|
}
|
|
9418
9618
|
have -= copy2;
|
|
9419
9619
|
next += copy2;
|
|
9420
|
-
if (
|
|
9620
|
+
if (len2) {
|
|
9421
9621
|
break inf_leave;
|
|
9422
9622
|
}
|
|
9423
9623
|
} else if (state.head) {
|
|
@@ -9659,7 +9859,7 @@ const inflate$2 = (strm, flush) => {
|
|
|
9659
9859
|
state.mode = BAD;
|
|
9660
9860
|
break;
|
|
9661
9861
|
}
|
|
9662
|
-
|
|
9862
|
+
len2 = state.lens[state.have - 1];
|
|
9663
9863
|
copy2 = 3 + (hold & 3);
|
|
9664
9864
|
hold >>>= 2;
|
|
9665
9865
|
bits -= 2;
|
|
@@ -9675,7 +9875,7 @@ const inflate$2 = (strm, flush) => {
|
|
|
9675
9875
|
}
|
|
9676
9876
|
hold >>>= here_bits;
|
|
9677
9877
|
bits -= here_bits;
|
|
9678
|
-
|
|
9878
|
+
len2 = 0;
|
|
9679
9879
|
copy2 = 3 + (hold & 7);
|
|
9680
9880
|
hold >>>= 3;
|
|
9681
9881
|
bits -= 3;
|
|
@@ -9691,7 +9891,7 @@ const inflate$2 = (strm, flush) => {
|
|
|
9691
9891
|
}
|
|
9692
9892
|
hold >>>= here_bits;
|
|
9693
9893
|
bits -= here_bits;
|
|
9694
|
-
|
|
9894
|
+
len2 = 0;
|
|
9695
9895
|
copy2 = 11 + (hold & 127);
|
|
9696
9896
|
hold >>>= 7;
|
|
9697
9897
|
bits -= 7;
|
|
@@ -9702,7 +9902,7 @@ const inflate$2 = (strm, flush) => {
|
|
|
9702
9902
|
break;
|
|
9703
9903
|
}
|
|
9704
9904
|
while (copy2--) {
|
|
9705
|
-
state.lens[state.have++] =
|
|
9905
|
+
state.lens[state.have++] = len2;
|
|
9706
9906
|
}
|
|
9707
9907
|
}
|
|
9708
9908
|
}
|
|
@@ -10432,7 +10632,40 @@ function v4(options, buf, offset) {
|
|
|
10432
10632
|
}
|
|
10433
10633
|
return stringify(rnds);
|
|
10434
10634
|
}
|
|
10435
|
-
|
|
10635
|
+
const Log = function(logLevel) {
|
|
10636
|
+
this.LOGGING_ON = true;
|
|
10637
|
+
this.LOGGING_OFF = false;
|
|
10638
|
+
this.LOG_PREFIX = "NiiVue:";
|
|
10639
|
+
this.logLevel = logLevel;
|
|
10640
|
+
};
|
|
10641
|
+
Log.prototype.getTimeStamp = function() {
|
|
10642
|
+
return `${this.LOG_PREFIX} `;
|
|
10643
|
+
};
|
|
10644
|
+
Log.prototype.debug = function() {
|
|
10645
|
+
if (this.logLevel === this.LOGGING_ON) {
|
|
10646
|
+
console.log(this.getTimeStamp(), "DEBUG", ...arguments);
|
|
10647
|
+
}
|
|
10648
|
+
};
|
|
10649
|
+
Log.prototype.info = function() {
|
|
10650
|
+
if (this.logLevel === this.LOGGING_ON) {
|
|
10651
|
+
console.log(this.getTimeStamp(), "INFO", ...arguments);
|
|
10652
|
+
}
|
|
10653
|
+
};
|
|
10654
|
+
Log.prototype.warn = function() {
|
|
10655
|
+
if (this.logLevel === this.LOGGING_ON) {
|
|
10656
|
+
console.warn(this.getTimeStamp(), "WARN", ...arguments);
|
|
10657
|
+
}
|
|
10658
|
+
};
|
|
10659
|
+
Log.prototype.error = function() {
|
|
10660
|
+
if (this.logLevel === this.LOGGING_ON) {
|
|
10661
|
+
console.error(this.getTimeStamp(), "ERROR", ...arguments);
|
|
10662
|
+
}
|
|
10663
|
+
};
|
|
10664
|
+
Log.prototype.setLogLevel = function(logLevel) {
|
|
10665
|
+
this.logLevel = logLevel;
|
|
10666
|
+
};
|
|
10667
|
+
const log$1 = new Log();
|
|
10668
|
+
var NVImage = function(dataBuffer, name = "", colorMap = "gray", opacity = 1, trustCalMinMax = true, percentileFrac = 0.02, ignoreZeroVoxels = false, visible = true, useQFormNotSForm = false) {
|
|
10436
10669
|
this.DT_NONE = 0;
|
|
10437
10670
|
this.DT_UNKNOWN = 0;
|
|
10438
10671
|
this.DT_BINARY = 1;
|
|
@@ -10465,6 +10698,97 @@ var NVImage = function(dataBuffer, name = "", colorMap = "gray", opacity = 1, tr
|
|
|
10465
10698
|
return;
|
|
10466
10699
|
}
|
|
10467
10700
|
this.hdr = nifti.exports.readHeader(dataBuffer);
|
|
10701
|
+
function isAffineOK(mtx) {
|
|
10702
|
+
let iOK = [false, false, false, false];
|
|
10703
|
+
let jOK = [false, false, false, false];
|
|
10704
|
+
for (let i2 = 0; i2 < 4; i2++) {
|
|
10705
|
+
for (let j = 0; j < 4; j++) {
|
|
10706
|
+
if (isNaN(mtx[i2][j]))
|
|
10707
|
+
return false;
|
|
10708
|
+
}
|
|
10709
|
+
}
|
|
10710
|
+
for (let i2 = 0; i2 < 3; i2++) {
|
|
10711
|
+
for (let j = 0; j < 3; j++) {
|
|
10712
|
+
if (mtx[i2][j] === 0)
|
|
10713
|
+
continue;
|
|
10714
|
+
iOK[i2] = true;
|
|
10715
|
+
jOK[j] = true;
|
|
10716
|
+
}
|
|
10717
|
+
}
|
|
10718
|
+
for (let i2 = 0; i2 < 3; i2++) {
|
|
10719
|
+
if (!iOK[i2])
|
|
10720
|
+
return false;
|
|
10721
|
+
if (!jOK[i2])
|
|
10722
|
+
return false;
|
|
10723
|
+
}
|
|
10724
|
+
return true;
|
|
10725
|
+
}
|
|
10726
|
+
if (isNaN(this.hdr.scl_slope) || this.hdr.scl_slope === 0)
|
|
10727
|
+
this.hdr.scl_slope = 1;
|
|
10728
|
+
if (isNaN(this.hdr.scl_inter))
|
|
10729
|
+
this.hdr.scl_inter = 0;
|
|
10730
|
+
let affineOK = isAffineOK(this.hdr.affine);
|
|
10731
|
+
if (useQFormNotSForm || !affineOK || this.hdr.qform_code > this.hdr.sform_code) {
|
|
10732
|
+
log$1.debug("spatial transform based on QForm");
|
|
10733
|
+
const b = this.hdr.quatern_b;
|
|
10734
|
+
const c = this.hdr.quatern_c;
|
|
10735
|
+
const d = this.hdr.quatern_d;
|
|
10736
|
+
const a = Math.sqrt(1 - (Math.pow(b, 2) + Math.pow(c, 2) + Math.pow(d, 2)));
|
|
10737
|
+
const qfac = this.hdr.pixDims[0] === 0 ? 1 : this.hdr.pixDims[0];
|
|
10738
|
+
const quatern_R = [
|
|
10739
|
+
[
|
|
10740
|
+
a * a + b * b - c * c - d * d,
|
|
10741
|
+
2 * b * c - 2 * a * d,
|
|
10742
|
+
2 * b * d + 2 * a * c
|
|
10743
|
+
],
|
|
10744
|
+
[
|
|
10745
|
+
2 * b * c + 2 * a * d,
|
|
10746
|
+
a * a + c * c - b * b - d * d,
|
|
10747
|
+
2 * c * d - 2 * a * b
|
|
10748
|
+
],
|
|
10749
|
+
[
|
|
10750
|
+
2 * b * d - 2 * a * c,
|
|
10751
|
+
2 * c * d + 2 * a * b,
|
|
10752
|
+
a * a + d * d - c * c - b * b
|
|
10753
|
+
]
|
|
10754
|
+
];
|
|
10755
|
+
const affine = this.hdr.affine;
|
|
10756
|
+
for (let ctrOut = 0; ctrOut < 3; ctrOut += 1) {
|
|
10757
|
+
for (let ctrIn = 0; ctrIn < 3; ctrIn += 1) {
|
|
10758
|
+
affine[ctrOut][ctrIn] = quatern_R[ctrOut][ctrIn] * this.hdr.pixDims[ctrIn + 1];
|
|
10759
|
+
if (ctrIn === 2) {
|
|
10760
|
+
affine[ctrOut][ctrIn] *= qfac;
|
|
10761
|
+
}
|
|
10762
|
+
}
|
|
10763
|
+
}
|
|
10764
|
+
affine[0][3] = this.hdr.qoffset_x;
|
|
10765
|
+
affine[1][3] = this.hdr.qoffset_y;
|
|
10766
|
+
affine[2][3] = this.hdr.qoffset_z;
|
|
10767
|
+
this.hdr.affine = affine;
|
|
10768
|
+
}
|
|
10769
|
+
affineOK = isAffineOK(this.hdr.affine);
|
|
10770
|
+
if (!affineOK) {
|
|
10771
|
+
log$1.debug("Defective NIfTI: spatial transform does not make sense");
|
|
10772
|
+
let x = this.hdr.pixDims[1];
|
|
10773
|
+
let y = this.hdr.pixDims[2];
|
|
10774
|
+
let z = this.hdr.pixDims[3];
|
|
10775
|
+
if (isNaN(x) || x === 0)
|
|
10776
|
+
x = 1;
|
|
10777
|
+
if (isNaN(y) || y === 0)
|
|
10778
|
+
y = 1;
|
|
10779
|
+
if (isNaN(z) || z === 0)
|
|
10780
|
+
z = 1;
|
|
10781
|
+
this.hdr.pixDims[1] = x;
|
|
10782
|
+
this.hdr.pixDims[2] = y;
|
|
10783
|
+
this.hdr.pixDims[3] = z;
|
|
10784
|
+
const affine = [
|
|
10785
|
+
[x, 0, 0, 0],
|
|
10786
|
+
[0, y, 0, 0],
|
|
10787
|
+
[0, 0, z, 0],
|
|
10788
|
+
[0, 0, 0, 1]
|
|
10789
|
+
];
|
|
10790
|
+
this.hdr.affine = affine;
|
|
10791
|
+
}
|
|
10468
10792
|
let imgRaw = null;
|
|
10469
10793
|
if (nifti.exports.isCompressed(dataBuffer)) {
|
|
10470
10794
|
imgRaw = nifti.exports.readImage(this.hdr, nifti.exports.decompress(dataBuffer));
|
|
@@ -10531,6 +10855,23 @@ var NVImage = function(dataBuffer, name = "", colorMap = "gray", opacity = 1, tr
|
|
|
10531
10855
|
this.calculateRAS();
|
|
10532
10856
|
this.calMinMax();
|
|
10533
10857
|
};
|
|
10858
|
+
NVImage.prototype.calculateOblique = function() {
|
|
10859
|
+
let LPI = this.vox2mm([0, 0, 0], this.matRAS);
|
|
10860
|
+
let X1mm = this.vox2mm([1 / this.pixDimsRAS[1], 0, 0], this.matRAS);
|
|
10861
|
+
let Y1mm = this.vox2mm([0, 1 / this.pixDimsRAS[2], 0], this.matRAS);
|
|
10862
|
+
let Z1mm = this.vox2mm([0, 0, 1 / this.pixDimsRAS[3]], this.matRAS);
|
|
10863
|
+
subtract(X1mm, X1mm, LPI);
|
|
10864
|
+
subtract(Y1mm, Y1mm, LPI);
|
|
10865
|
+
subtract(Z1mm, Z1mm, LPI);
|
|
10866
|
+
let oblique = fromValues$2(X1mm[0], X1mm[1], X1mm[2], 0, Y1mm[0], Y1mm[1], Y1mm[2], 0, Z1mm[0], Z1mm[1], Z1mm[2], 0, 0, 0, 0, 1);
|
|
10867
|
+
this.obliqueRAS = clone$1(oblique);
|
|
10868
|
+
let XY = Math.abs(90 - angle(X1mm, Y1mm) * (180 / Math.PI));
|
|
10869
|
+
let XZ = Math.abs(90 - angle(X1mm, Z1mm) * (180 / Math.PI));
|
|
10870
|
+
let YZ = Math.abs(90 - angle(Y1mm, Z1mm) * (180 / Math.PI));
|
|
10871
|
+
let maxShear = Math.max(Math.max(XY, XZ), YZ);
|
|
10872
|
+
if (maxShear > 0.1)
|
|
10873
|
+
log$1.debug("Warning: shear detected (gantry tilt) of %f degrees", maxShear);
|
|
10874
|
+
};
|
|
10534
10875
|
NVImage.prototype.calculateRAS = function() {
|
|
10535
10876
|
let a = this.hdr.affine;
|
|
10536
10877
|
let header = this.hdr;
|
|
@@ -10573,7 +10914,7 @@ NVImage.prototype.calculateRAS = function() {
|
|
|
10573
10914
|
this.mm010 = this.vox2mm([-0.5, header.dims[2] - 0.5, -0.5], rotM);
|
|
10574
10915
|
this.mm001 = this.vox2mm([-0.5, -0.5, header.dims[3] - 0.5], rotM);
|
|
10575
10916
|
let R2 = create$2();
|
|
10576
|
-
copy(R2, rotM);
|
|
10917
|
+
copy$1(R2, rotM);
|
|
10577
10918
|
for (let i = 0; i < 3; i++) {
|
|
10578
10919
|
for (let j = 0; j < 3; j++) {
|
|
10579
10920
|
R2[i * 4 + j] = rotM[i * 4 + perm[j] - 1];
|
|
@@ -10603,7 +10944,8 @@ NVImage.prototype.calculateRAS = function() {
|
|
|
10603
10944
|
];
|
|
10604
10945
|
if (this.arrayEquals(perm, [1, 2, 3]) && this.arrayEquals(flip, [0, 0, 0])) {
|
|
10605
10946
|
this.toRAS = create$2();
|
|
10606
|
-
this.matRAS = clone(rotM);
|
|
10947
|
+
this.matRAS = clone$1(rotM);
|
|
10948
|
+
this.calculateOblique();
|
|
10607
10949
|
return;
|
|
10608
10950
|
}
|
|
10609
10951
|
identity$1(rotM);
|
|
@@ -10616,7 +10958,7 @@ NVImage.prototype.calculateRAS = function() {
|
|
|
10616
10958
|
let residualR = create$2();
|
|
10617
10959
|
invert(residualR, rotM);
|
|
10618
10960
|
multiply$1(residualR, residualR, R2);
|
|
10619
|
-
this.matRAS = clone(residualR);
|
|
10961
|
+
this.matRAS = clone$1(residualR);
|
|
10620
10962
|
rotM = fromValues$2(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
|
|
10621
10963
|
rotM[perm[0] - 1 + 0 * 4] = -flip[0] * 2 + 1;
|
|
10622
10964
|
rotM[perm[1] - 1 + 1 * 4] = -flip[1] * 2 + 1;
|
|
@@ -10624,12 +10966,13 @@ NVImage.prototype.calculateRAS = function() {
|
|
|
10624
10966
|
rotM[3 + 0 * 4] = flip[0];
|
|
10625
10967
|
rotM[3 + 1 * 4] = flip[1];
|
|
10626
10968
|
rotM[3 + 2 * 4] = flip[2];
|
|
10627
|
-
this.toRAS = clone(rotM);
|
|
10628
|
-
|
|
10629
|
-
|
|
10969
|
+
this.toRAS = clone$1(rotM);
|
|
10970
|
+
log$1.debug(this.hdr.dims);
|
|
10971
|
+
log$1.debug(this.dimsRAS);
|
|
10972
|
+
this.calculateOblique();
|
|
10630
10973
|
};
|
|
10631
10974
|
NVImage.prototype.vox2mm = function(XYZ, mtx) {
|
|
10632
|
-
let sform = clone(mtx);
|
|
10975
|
+
let sform = clone$1(mtx);
|
|
10633
10976
|
transpose(sform, sform);
|
|
10634
10977
|
let pos = fromValues(XYZ[0], XYZ[1], XYZ[2], 1);
|
|
10635
10978
|
transformMat4(pos, pos, sform);
|
|
@@ -10638,7 +10981,7 @@ NVImage.prototype.vox2mm = function(XYZ, mtx) {
|
|
|
10638
10981
|
};
|
|
10639
10982
|
NVImage.prototype.mm2vox = function(mm) {
|
|
10640
10983
|
let sform = fromValues$2(...this.hdr.affine.flat());
|
|
10641
|
-
let out = clone(sform);
|
|
10984
|
+
let out = clone$1(sform);
|
|
10642
10985
|
transpose(out, sform);
|
|
10643
10986
|
invert(out, out);
|
|
10644
10987
|
let pos = fromValues(mm[0], mm[1], mm[2], 1);
|
|
@@ -10660,6 +11003,8 @@ NVImage.prototype.calMinMax = function() {
|
|
|
10660
11003
|
if (this.trustCalMinMax && isFinite(this.hdr.cal_min) && isFinite(this.hdr.cal_max) && this.hdr.cal_max > this.hdr.cal_min) {
|
|
10661
11004
|
this.cal_min = this.hdr.cal_min;
|
|
10662
11005
|
this.cal_max = this.hdr.cal_max;
|
|
11006
|
+
this.robust_min = this.cal_min;
|
|
11007
|
+
this.robust_max = this.cal_max;
|
|
10663
11008
|
this.global_min = this.hdr.cal_min;
|
|
10664
11009
|
this.global_max = this.hdr.cal_max;
|
|
10665
11010
|
return [
|
|
@@ -10680,6 +11025,8 @@ NVImage.prototype.calMinMax = function() {
|
|
|
10680
11025
|
if (cmMin != cmMax) {
|
|
10681
11026
|
this.cal_min = cmMin;
|
|
10682
11027
|
this.cal_max = cmMax;
|
|
11028
|
+
this.robust_min = this.cal_min;
|
|
11029
|
+
this.robust_max = this.cal_max;
|
|
10683
11030
|
return [cmMin, cmMax, cmMin, cmMax];
|
|
10684
11031
|
}
|
|
10685
11032
|
let mn = this.img[0];
|
|
@@ -10708,9 +11055,11 @@ NVImage.prototype.calMinMax = function() {
|
|
|
10708
11055
|
nZero += nNan;
|
|
10709
11056
|
let n2pct = Math.round((nVox - nZero) * this.percentileFrac);
|
|
10710
11057
|
if (n2pct < 1 || mn === mx) {
|
|
10711
|
-
|
|
11058
|
+
log$1.debug("no variability in image intensity?");
|
|
10712
11059
|
this.cal_min = mnScale;
|
|
10713
11060
|
this.cal_max = mxScale;
|
|
11061
|
+
this.robust_min = this.cal_min;
|
|
11062
|
+
this.robust_max = this.cal_max;
|
|
10714
11063
|
this.global_min = mnScale;
|
|
10715
11064
|
this.global_max = mxScale;
|
|
10716
11065
|
return [mnScale, mxScale, mnScale, mxScale];
|
|
@@ -10775,6 +11124,8 @@ NVImage.prototype.calMinMax = function() {
|
|
|
10775
11124
|
}
|
|
10776
11125
|
this.cal_min = pct2;
|
|
10777
11126
|
this.cal_max = pct98;
|
|
11127
|
+
this.robust_min = this.cal_min;
|
|
11128
|
+
this.robust_max = this.cal_max;
|
|
10778
11129
|
this.global_min = mnScale;
|
|
10779
11130
|
this.global_max = mxScale;
|
|
10780
11131
|
return [pct2, pct98, mnScale, mxScale];
|
|
@@ -10816,7 +11167,7 @@ NVImage.loadFromFile = async function(file, name = "", colorMap = "gray", opacit
|
|
|
10816
11167
|
let dataBuffer = await this.readFileAsync(file);
|
|
10817
11168
|
nvimage = new NVImage(dataBuffer, name, colorMap, opacity, trustCalMinMax, percentileFrac, ignoreZeroVoxels, visible);
|
|
10818
11169
|
} catch (err2) {
|
|
10819
|
-
|
|
11170
|
+
log$1.debug(err2);
|
|
10820
11171
|
}
|
|
10821
11172
|
return nvimage;
|
|
10822
11173
|
};
|
|
@@ -10882,138 +11233,69 @@ NVImage.prototype.getValue = function(x, y, z) {
|
|
|
10882
11233
|
let vx = 3 * (x + y * nx + z * nx * ny);
|
|
10883
11234
|
return Math.round(this.img[vx] * 0.21 + this.img[vx + 1] * 0.72 + this.img[vx + 2] * 0.07);
|
|
10884
11235
|
}
|
|
10885
|
-
|
|
11236
|
+
let i = this.img[x + y * nx + z * nx * ny];
|
|
11237
|
+
return this.hdr.scl_slope * i + this.hdr.scl_inter;
|
|
10886
11238
|
};
|
|
10887
|
-
function getExtents(positions) {
|
|
10888
|
-
|
|
10889
|
-
|
|
11239
|
+
function getExtents(positions, forceOriginInVolume = true) {
|
|
11240
|
+
let nV = (positions.length / 3).toFixed();
|
|
11241
|
+
let origin = fromValues$1(0, 0, 0);
|
|
11242
|
+
let mn = create$1();
|
|
11243
|
+
let mx = create$1();
|
|
10890
11244
|
let mxDx = 0;
|
|
10891
|
-
|
|
11245
|
+
let nLoops = 1;
|
|
11246
|
+
if (forceOriginInVolume)
|
|
11247
|
+
nLoops = 2;
|
|
11248
|
+
for (let loop = 0; loop < nLoops; loop++) {
|
|
11249
|
+
mxDx = 0;
|
|
11250
|
+
for (let i = 0; i < nV; i++) {
|
|
11251
|
+
let v = fromValues$1(positions[i * 3], positions[i * 3 + 1], positions[i * 3 + 2]);
|
|
11252
|
+
if (i === 0) {
|
|
11253
|
+
copy(mn, v);
|
|
11254
|
+
copy(mx, v);
|
|
11255
|
+
}
|
|
11256
|
+
min$Q(mn, mn, v);
|
|
11257
|
+
max$Q(mx, mx, v);
|
|
11258
|
+
subtract(v, v, origin);
|
|
11259
|
+
let dx = len(v);
|
|
11260
|
+
mxDx = Math.max(mxDx, dx);
|
|
11261
|
+
}
|
|
11262
|
+
if (loop + 1 >= nLoops)
|
|
11263
|
+
break;
|
|
11264
|
+
let ok = true;
|
|
10892
11265
|
for (let j = 0; j < 3; ++j) {
|
|
10893
|
-
|
|
10894
|
-
|
|
10895
|
-
|
|
11266
|
+
if (mn[j] > origin[j])
|
|
11267
|
+
ok = false;
|
|
11268
|
+
if (mx[j] < origin[j])
|
|
11269
|
+
ok = false;
|
|
10896
11270
|
}
|
|
10897
|
-
|
|
10898
|
-
|
|
11271
|
+
if (ok)
|
|
11272
|
+
break;
|
|
11273
|
+
lerp(origin, mn, mx, 0.5);
|
|
11274
|
+
log$1.debug("origin moved inside volume: ", origin);
|
|
10899
11275
|
}
|
|
10900
|
-
let
|
|
10901
|
-
|
|
11276
|
+
let min2 = [mn[0], mn[1], mn[2]];
|
|
11277
|
+
let max2 = [mx[0], mx[1], mx[2]];
|
|
11278
|
+
let furthestVertexFromOrigin = mxDx;
|
|
11279
|
+
return { min: min2, max: max2, furthestVertexFromOrigin, origin };
|
|
10902
11280
|
}
|
|
10903
|
-
NVImage.prototype.method1 = function() {
|
|
10904
|
-
return {
|
|
10905
|
-
left: -(this.dimsRAS[1] / 2) * this.pixDimsRAS[1],
|
|
10906
|
-
right: this.dimsRAS[1] / 2 * this.pixDimsRAS[1],
|
|
10907
|
-
posterior: -(this.dimsRAS[2] / 2) * this.pixDimsRAS[2],
|
|
10908
|
-
anterior: this.dimsRAS[2] / 2 * this.pixDimsRAS[2],
|
|
10909
|
-
inferior: -(this.dimsRAS[3] / 2) * this.pixDimsRAS[3],
|
|
10910
|
-
superior: this.dimsRAS[3] / 2 * this.pixDimsRAS[3]
|
|
10911
|
-
};
|
|
10912
|
-
};
|
|
10913
|
-
NVImage.prototype.method2 = function() {
|
|
10914
|
-
const affine = [];
|
|
10915
|
-
for (let i = 0; i < 4; i++) {
|
|
10916
|
-
for (let j = 0; j < 4; j++) {
|
|
10917
|
-
affine.push(this.hdr.affine[i][j]);
|
|
10918
|
-
}
|
|
10919
|
-
}
|
|
10920
|
-
const affineMatrix = fromValues$2(...affine);
|
|
10921
|
-
const qfac = this.hdr.dims[0] ? this.hdr.pixDims[0] : 1;
|
|
10922
|
-
let rightTopFront = fromValues(this.hdr.dims[1] * this.hdr.pixDims[1], this.hdr.dims[2] * this.hdr.pixDims[2], qfac * this.hdr.dims[3] * this.hdr.pixDims[3], 1);
|
|
10923
|
-
let maxExtent = create();
|
|
10924
|
-
transformMat4(maxExtent, rightTopFront, affineMatrix);
|
|
10925
|
-
return {
|
|
10926
|
-
left: maxExtent[0] / 2,
|
|
10927
|
-
right: 0 - maxExtent[0] / 2,
|
|
10928
|
-
posterior: 0 - maxExtent[1] / 2,
|
|
10929
|
-
anterior: maxExtent[1] / 2,
|
|
10930
|
-
inferior: 0 - maxExtent[2] / 2,
|
|
10931
|
-
superior: maxExtent[2] / 2
|
|
10932
|
-
};
|
|
10933
|
-
};
|
|
10934
|
-
NVImage.prototype.method3 = function() {
|
|
10935
|
-
};
|
|
10936
11281
|
NVImage.prototype.toNiivueObject3D = function(id, gl) {
|
|
10937
|
-
let
|
|
10938
|
-
let
|
|
10939
|
-
let
|
|
10940
|
-
let
|
|
10941
|
-
let
|
|
10942
|
-
let
|
|
10943
|
-
let
|
|
11282
|
+
let LPI = this.vox2mm([0, 0, 0], this.matRAS);
|
|
11283
|
+
let LAI = this.vox2mm([0, this.dimsRAS[2] - 1, 0], this.matRAS);
|
|
11284
|
+
let LPS = this.vox2mm([0, 0, this.dimsRAS[3] - 1], this.matRAS);
|
|
11285
|
+
let LAS = this.vox2mm([0, this.dimsRAS[2] - 1, this.dimsRAS[3] - 1], this.matRAS);
|
|
11286
|
+
let RPI = this.vox2mm([this.dimsRAS[1] - 1, 0, 0], this.matRAS);
|
|
11287
|
+
let RAI = this.vox2mm([this.dimsRAS[1] - 1, this.dimsRAS[2] - 1, 0], this.matRAS);
|
|
11288
|
+
let RPS = this.vox2mm([this.dimsRAS[1] - 1, 0, this.dimsRAS[3] - 1], this.matRAS);
|
|
11289
|
+
let RAS = this.vox2mm([this.dimsRAS[1] - 1, this.dimsRAS[2] - 1, this.dimsRAS[3] - 1], this.matRAS);
|
|
10944
11290
|
const positions = [
|
|
10945
|
-
|
|
10946
|
-
|
|
10947
|
-
|
|
10948
|
-
|
|
10949
|
-
|
|
10950
|
-
|
|
10951
|
-
|
|
10952
|
-
|
|
10953
|
-
superior,
|
|
10954
|
-
left,
|
|
10955
|
-
anterior,
|
|
10956
|
-
superior,
|
|
10957
|
-
left,
|
|
10958
|
-
posterior,
|
|
10959
|
-
inferior,
|
|
10960
|
-
left,
|
|
10961
|
-
anterior,
|
|
10962
|
-
inferior,
|
|
10963
|
-
right,
|
|
10964
|
-
anterior,
|
|
10965
|
-
inferior,
|
|
10966
|
-
right,
|
|
10967
|
-
posterior,
|
|
10968
|
-
inferior,
|
|
10969
|
-
left,
|
|
10970
|
-
anterior,
|
|
10971
|
-
inferior,
|
|
10972
|
-
left,
|
|
10973
|
-
anterior,
|
|
10974
|
-
superior,
|
|
10975
|
-
right,
|
|
10976
|
-
anterior,
|
|
10977
|
-
superior,
|
|
10978
|
-
right,
|
|
10979
|
-
anterior,
|
|
10980
|
-
inferior,
|
|
10981
|
-
left,
|
|
10982
|
-
posterior,
|
|
10983
|
-
inferior,
|
|
10984
|
-
right,
|
|
10985
|
-
posterior,
|
|
10986
|
-
inferior,
|
|
10987
|
-
right,
|
|
10988
|
-
posterior,
|
|
10989
|
-
superior,
|
|
10990
|
-
left,
|
|
10991
|
-
posterior,
|
|
10992
|
-
superior,
|
|
10993
|
-
right,
|
|
10994
|
-
posterior,
|
|
10995
|
-
inferior,
|
|
10996
|
-
right,
|
|
10997
|
-
anterior,
|
|
10998
|
-
inferior,
|
|
10999
|
-
right,
|
|
11000
|
-
anterior,
|
|
11001
|
-
superior,
|
|
11002
|
-
right,
|
|
11003
|
-
posterior,
|
|
11004
|
-
superior,
|
|
11005
|
-
left,
|
|
11006
|
-
posterior,
|
|
11007
|
-
inferior,
|
|
11008
|
-
left,
|
|
11009
|
-
posterior,
|
|
11010
|
-
superior,
|
|
11011
|
-
left,
|
|
11012
|
-
anterior,
|
|
11013
|
-
superior,
|
|
11014
|
-
left,
|
|
11015
|
-
anterior,
|
|
11016
|
-
inferior
|
|
11291
|
+
...LPS,
|
|
11292
|
+
...RPS,
|
|
11293
|
+
...RAS,
|
|
11294
|
+
...LAS,
|
|
11295
|
+
...LPI,
|
|
11296
|
+
...LAI,
|
|
11297
|
+
...RAI,
|
|
11298
|
+
...RPI
|
|
11017
11299
|
];
|
|
11018
11300
|
const textureCoordinates = [
|
|
11019
11301
|
0,
|
|
@@ -11107,30 +11389,30 @@ NVImage.prototype.toNiivueObject3D = function(id, gl) {
|
|
|
11107
11389
|
6,
|
|
11108
11390
|
5,
|
|
11109
11391
|
4,
|
|
11110
|
-
|
|
11111
|
-
|
|
11112
|
-
|
|
11113
|
-
|
|
11114
|
-
|
|
11115
|
-
|
|
11116
|
-
|
|
11117
|
-
|
|
11118
|
-
|
|
11119
|
-
|
|
11120
|
-
|
|
11121
|
-
|
|
11122
|
-
|
|
11123
|
-
|
|
11124
|
-
|
|
11125
|
-
|
|
11126
|
-
|
|
11127
|
-
|
|
11128
|
-
|
|
11129
|
-
|
|
11130
|
-
|
|
11131
|
-
|
|
11132
|
-
|
|
11133
|
-
|
|
11392
|
+
5,
|
|
11393
|
+
6,
|
|
11394
|
+
2,
|
|
11395
|
+
2,
|
|
11396
|
+
3,
|
|
11397
|
+
5,
|
|
11398
|
+
4,
|
|
11399
|
+
0,
|
|
11400
|
+
1,
|
|
11401
|
+
1,
|
|
11402
|
+
7,
|
|
11403
|
+
4,
|
|
11404
|
+
7,
|
|
11405
|
+
1,
|
|
11406
|
+
2,
|
|
11407
|
+
2,
|
|
11408
|
+
6,
|
|
11409
|
+
7,
|
|
11410
|
+
4,
|
|
11411
|
+
5,
|
|
11412
|
+
3,
|
|
11413
|
+
3,
|
|
11414
|
+
0,
|
|
11415
|
+
4
|
|
11134
11416
|
];
|
|
11135
11417
|
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
|
|
11136
11418
|
const textureCoordBuffer = gl.createBuffer();
|
|
@@ -11141,40 +11423,10 @@ NVImage.prototype.toNiivueObject3D = function(id, gl) {
|
|
|
11141
11423
|
obj3D.extentsMin = extents.min;
|
|
11142
11424
|
obj3D.extentsMax = extents.max;
|
|
11143
11425
|
obj3D.furthestVertexFromOrigin = extents.furthestVertexFromOrigin;
|
|
11426
|
+
obj3D.originNegate = clone(extents.origin);
|
|
11427
|
+
negate(obj3D.originNegate, obj3D.originNegate);
|
|
11144
11428
|
return obj3D;
|
|
11145
11429
|
};
|
|
11146
|
-
const Log = function(logLevel) {
|
|
11147
|
-
this.LOGGING_ON = true;
|
|
11148
|
-
this.LOGGING_OFF = false;
|
|
11149
|
-
this.LOG_PREFIX = "NiiVue:";
|
|
11150
|
-
this.logLevel = logLevel;
|
|
11151
|
-
};
|
|
11152
|
-
Log.prototype.getTimeStamp = function() {
|
|
11153
|
-
return `${this.LOG_PREFIX} `;
|
|
11154
|
-
};
|
|
11155
|
-
Log.prototype.debug = function() {
|
|
11156
|
-
if (this.logLevel === this.LOGGING_ON) {
|
|
11157
|
-
console.log(this.getTimeStamp(), "DEBUG", ...arguments);
|
|
11158
|
-
}
|
|
11159
|
-
};
|
|
11160
|
-
Log.prototype.info = function() {
|
|
11161
|
-
if (this.logLevel === this.LOGGING_ON) {
|
|
11162
|
-
console.log(this.getTimeStamp(), "INFO", ...arguments);
|
|
11163
|
-
}
|
|
11164
|
-
};
|
|
11165
|
-
Log.prototype.warn = function() {
|
|
11166
|
-
if (this.logLevel === this.LOGGING_ON) {
|
|
11167
|
-
console.warn(this.getTimeStamp(), "WARN", ...arguments);
|
|
11168
|
-
}
|
|
11169
|
-
};
|
|
11170
|
-
Log.prototype.error = function() {
|
|
11171
|
-
if (this.logLevel === this.LOGGING_ON) {
|
|
11172
|
-
console.error(this.getTimeStamp(), "ERROR", ...arguments);
|
|
11173
|
-
}
|
|
11174
|
-
};
|
|
11175
|
-
Log.prototype.setLogLevel = function(logLevel) {
|
|
11176
|
-
this.logLevel = logLevel;
|
|
11177
|
-
};
|
|
11178
11430
|
var defaultFontPNG = "data:image/png;base64,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";
|
|
11179
11431
|
const atlas = {
|
|
11180
11432
|
type: "msdf",
|
|
@@ -12713,20 +12965,25 @@ const log = new Log();
|
|
|
12713
12965
|
const Niivue = function(options = {}) {
|
|
12714
12966
|
this.opts = {};
|
|
12715
12967
|
this.defaults = {
|
|
12716
|
-
textHeight: 0.
|
|
12968
|
+
textHeight: 0.06,
|
|
12717
12969
|
colorbarHeight: 0.05,
|
|
12718
12970
|
crosshairWidth: 1,
|
|
12971
|
+
show3Dcrosshair: false,
|
|
12719
12972
|
backColor: [0, 0, 0, 1],
|
|
12720
12973
|
crosshairColor: [1, 0, 0, 1],
|
|
12721
12974
|
selectionBoxColor: [1, 1, 1, 0.5],
|
|
12722
|
-
clipPlaneColor: [
|
|
12975
|
+
clipPlaneColor: [0.7, 0, 0.7, 0.5],
|
|
12723
12976
|
colorBarMargin: 0.05,
|
|
12724
12977
|
trustCalMinMax: true,
|
|
12725
12978
|
clipPlaneHotKey: "KeyC",
|
|
12726
12979
|
viewModeHotKey: "KeyV",
|
|
12727
12980
|
keyDebounceTime: 50,
|
|
12981
|
+
isNearestInterpolation: false,
|
|
12982
|
+
isAtlasOutline: false,
|
|
12728
12983
|
isRadiologicalConvention: false,
|
|
12729
|
-
logging: false
|
|
12984
|
+
logging: false,
|
|
12985
|
+
loadingText: "waiting for images...",
|
|
12986
|
+
dragAndDropEnabled: true
|
|
12730
12987
|
};
|
|
12731
12988
|
this.canvas = null;
|
|
12732
12989
|
this.gl = null;
|
|
@@ -12736,14 +12993,17 @@ const Niivue = function(options = {}) {
|
|
|
12736
12993
|
this.sliceShader = null;
|
|
12737
12994
|
this.lineShader = null;
|
|
12738
12995
|
this.renderShader = null;
|
|
12996
|
+
this.pickingShader = null;
|
|
12739
12997
|
this.colorbarShader = null;
|
|
12740
12998
|
this.fontShader = null;
|
|
12741
12999
|
this.passThroughShader = null;
|
|
13000
|
+
this.orientShaderAtlasU = null;
|
|
12742
13001
|
this.orientShaderU = null;
|
|
12743
13002
|
this.orientShaderI = null;
|
|
12744
13003
|
this.orientShaderF = null;
|
|
12745
13004
|
this.orientShaderRGBU = null;
|
|
12746
13005
|
this.surfaceShader = null;
|
|
13006
|
+
this.crosshairs3D = null;
|
|
12747
13007
|
this.pickingSurfaceShader = null;
|
|
12748
13008
|
this.DEFAULT_FONT_GLYPH_SHEET = defaultFontPNG;
|
|
12749
13009
|
this.DEFAULT_FONT_METRICS = defaultFontMetrics;
|
|
@@ -12755,16 +13015,19 @@ const Niivue = function(options = {}) {
|
|
|
12755
13015
|
this.sliceTypeRender = 4;
|
|
12756
13016
|
this.sliceType = this.sliceTypeMultiplanar;
|
|
12757
13017
|
this.scene = {};
|
|
13018
|
+
this.syncOpts = {};
|
|
12758
13019
|
this.scene.renderAzimuth = 110;
|
|
12759
|
-
this.scene.renderElevation =
|
|
13020
|
+
this.scene.renderElevation = 10;
|
|
12760
13021
|
this.scene.crosshairPos = [0.5, 0.5, 0.5];
|
|
12761
13022
|
this.scene.clipPlane = [0, 0, 0, 0];
|
|
13023
|
+
this.scene.clipPlaneDepthAziElev = [2, 0, 0];
|
|
12762
13024
|
this.scene.mousedown = false;
|
|
12763
13025
|
this.scene.touchdown = false;
|
|
12764
13026
|
this.scene.mouseButtonLeft = 0;
|
|
12765
13027
|
this.scene.mouseButtonRight = 2;
|
|
12766
13028
|
this.scene.mouseButtonLeftDown = false;
|
|
12767
13029
|
this.scene.mouseButtonRightDown = false;
|
|
13030
|
+
this.scene.mouseDepthPicker = false;
|
|
12768
13031
|
this.scene.prevX = 0;
|
|
12769
13032
|
this.scene.prevY = 0;
|
|
12770
13033
|
this.scene.currX = 0;
|
|
@@ -12785,30 +13048,29 @@ const Niivue = function(options = {}) {
|
|
|
12785
13048
|
{ leftTopWidthHeight: [1, 0, 0, 1], axCorSag: this.sliceTypeAxial },
|
|
12786
13049
|
{ leftTopWidthHeight: [1, 0, 0, 1], axCorSag: this.sliceTypeAxial }
|
|
12787
13050
|
];
|
|
12788
|
-
this.backOpacity = 1;
|
|
12789
13051
|
this.isDragging = false;
|
|
12790
13052
|
this.dragStart = [0, 0];
|
|
12791
13053
|
this.dragEnd = [0, 0];
|
|
13054
|
+
this.dragClipPlaneStartDepthAziElev = [0, 0, 0];
|
|
12792
13055
|
this.lastTwoTouchDistance = 0;
|
|
12793
13056
|
this.otherNV = null;
|
|
12794
13057
|
this.volumeObject3D = null;
|
|
12795
|
-
this.clipPlaneObject3D = null;
|
|
12796
13058
|
this.intensityRange$ = new Subject();
|
|
12797
13059
|
this.scene.location$ = new Subject();
|
|
12798
13060
|
this.scene.loading$ = new Subject();
|
|
12799
|
-
this.loadingText = "waiting for images...";
|
|
12800
13061
|
this.currentClipPlaneIndex = 0;
|
|
12801
13062
|
this.lastCalled = new Date().getTime();
|
|
12802
13063
|
this.multiTouchGesture = false;
|
|
12803
13064
|
this.gestureInterval = null;
|
|
12804
13065
|
this.selectedObjectId = -1;
|
|
12805
13066
|
this.CLIP_PLANE_ID = 1;
|
|
12806
|
-
this.VOLUME_ID =
|
|
13067
|
+
this.VOLUME_ID = 254;
|
|
12807
13068
|
this.DISTANCE_FROM_CAMERA = -0.54;
|
|
12808
13069
|
this.initialized = false;
|
|
12809
13070
|
for (let prop in this.defaults) {
|
|
12810
13071
|
this.opts[prop] = options[prop] === void 0 ? this.defaults[prop] : options[prop];
|
|
12811
13072
|
}
|
|
13073
|
+
this.loadingText = this.opts.loadingText;
|
|
12812
13074
|
log.setLogLevel(this.opts.logging);
|
|
12813
13075
|
this.eventsToSubjects = {
|
|
12814
13076
|
location: this.scene.location$,
|
|
@@ -12852,7 +13114,7 @@ Niivue.prototype.attachToCanvas = async function(canvas) {
|
|
|
12852
13114
|
this.gl = this.canvas.getContext("webgl2");
|
|
12853
13115
|
if (!this.gl) {
|
|
12854
13116
|
alert("unable to get webgl2 context. Perhaps this browser does not support webgl2");
|
|
12855
|
-
|
|
13117
|
+
log.warn("unable to get webgl2 context. Perhaps this browser does not support webgl2");
|
|
12856
13118
|
}
|
|
12857
13119
|
this.canvas.parentElement.style.backgroundColor = "black";
|
|
12858
13120
|
this.canvas.style.width = "100%";
|
|
@@ -12865,17 +13127,22 @@ Niivue.prototype.attachToCanvas = async function(canvas) {
|
|
|
12865
13127
|
this.drawScene();
|
|
12866
13128
|
return this;
|
|
12867
13129
|
};
|
|
12868
|
-
Niivue.prototype.syncWith = function(otherNV) {
|
|
13130
|
+
Niivue.prototype.syncWith = function(otherNV, syncOpts = { "2d": true, "3d": true }) {
|
|
12869
13131
|
this.otherNV = otherNV;
|
|
13132
|
+
this.syncOpts = syncOpts;
|
|
12870
13133
|
};
|
|
12871
13134
|
Niivue.prototype.sync = function() {
|
|
12872
13135
|
if (!this.otherNV || typeof this.otherNV === "undefined") {
|
|
12873
13136
|
return;
|
|
12874
13137
|
}
|
|
12875
13138
|
let thisMM = this.frac2mm(this.scene.crosshairPos);
|
|
12876
|
-
|
|
12877
|
-
|
|
12878
|
-
|
|
13139
|
+
if (this.syncOpts["2d"]) {
|
|
13140
|
+
this.otherNV.scene.crosshairPos = this.otherNV.mm2frac(thisMM);
|
|
13141
|
+
}
|
|
13142
|
+
if (this.syncOpts["3d"]) {
|
|
13143
|
+
this.otherNV.scene.renderAzimuth = this.scene.renderAzimuth;
|
|
13144
|
+
this.otherNV.scene.renderElevation = this.scene.renderElevation;
|
|
13145
|
+
}
|
|
12879
13146
|
this.otherNV.drawScene();
|
|
12880
13147
|
};
|
|
12881
13148
|
Niivue.prototype.arrayEquals = function(a, b) {
|
|
@@ -12927,6 +13194,7 @@ Niivue.prototype.mouseRightButtonHandler = function(e) {
|
|
|
12927
13194
|
let pos = this.getNoPaddingNoBorderCanvasRelativeMousePosition(e, this.gl.canvas);
|
|
12928
13195
|
this.dragStart[0] = pos.x;
|
|
12929
13196
|
this.dragStart[1] = pos.y;
|
|
13197
|
+
this.dragClipPlaneStartDepthAziElev = this.scene.clipPlaneDepthAziElev;
|
|
12930
13198
|
return;
|
|
12931
13199
|
};
|
|
12932
13200
|
Niivue.prototype.calculateMinMaxVoxIdx = function(array) {
|
|
@@ -12998,8 +13266,8 @@ Niivue.prototype.mouseUpListener = function() {
|
|
|
12998
13266
|
this.isDragging = false;
|
|
12999
13267
|
this.calculateNewRange();
|
|
13000
13268
|
this.refreshLayers(this.volumes[0], 0, this.volumes.length);
|
|
13001
|
-
this.drawScene();
|
|
13002
13269
|
}
|
|
13270
|
+
this.drawScene();
|
|
13003
13271
|
};
|
|
13004
13272
|
Niivue.prototype.checkMultitouch = function(e) {
|
|
13005
13273
|
if (this.scene.touchdown && !this.multiTouchGesture) {
|
|
@@ -13039,8 +13307,13 @@ Niivue.prototype.mouseMoveListener = function(e) {
|
|
|
13039
13307
|
}
|
|
13040
13308
|
};
|
|
13041
13309
|
Niivue.prototype.resetBriCon = function() {
|
|
13042
|
-
this.
|
|
13043
|
-
|
|
13310
|
+
if (this.sliceType === this.sliceTypeRender) {
|
|
13311
|
+
this.scene.mouseDepthPicker = true;
|
|
13312
|
+
this.drawScene();
|
|
13313
|
+
return;
|
|
13314
|
+
}
|
|
13315
|
+
this.volumes[0].cal_min = this.volumes[0].robust_min;
|
|
13316
|
+
this.volumes[0].cal_max = this.volumes[0].robust_max;
|
|
13044
13317
|
this.refreshLayers(this.volumes[0], 0, this.volumes.length);
|
|
13045
13318
|
this.drawScene();
|
|
13046
13319
|
};
|
|
@@ -13077,27 +13350,31 @@ Niivue.prototype.keyUpListener = function(e) {
|
|
|
13077
13350
|
let now = new Date().getTime();
|
|
13078
13351
|
let elapsed = now - this.lastCalled;
|
|
13079
13352
|
if (elapsed > this.opts.keyDebounceTime) {
|
|
13080
|
-
this.currentClipPlaneIndex = (this.currentClipPlaneIndex + 1) %
|
|
13081
|
-
this.clipPlaneObject3D.isVisible = this.currentClipPlaneIndex;
|
|
13353
|
+
this.currentClipPlaneIndex = (this.currentClipPlaneIndex + 1) % 7;
|
|
13082
13354
|
switch (this.currentClipPlaneIndex) {
|
|
13083
13355
|
case 0:
|
|
13084
|
-
this.scene.
|
|
13085
|
-
this.clipPlaneObject3D.rotation = [0, 0, 0];
|
|
13356
|
+
this.scene.clipPlaneDepthAziElev = [2, 0, 0];
|
|
13086
13357
|
break;
|
|
13087
13358
|
case 1:
|
|
13088
|
-
this.scene.
|
|
13089
|
-
this.clipPlaneObject3D.rotation = [0, 1, 0];
|
|
13359
|
+
this.scene.clipPlaneDepthAziElev = [0, 270, 0];
|
|
13090
13360
|
break;
|
|
13091
13361
|
case 2:
|
|
13092
|
-
this.scene.
|
|
13093
|
-
this.clipPlaneObject3D.rotation = [1, 0, 0];
|
|
13362
|
+
this.scene.clipPlaneDepthAziElev = [0, 90, 0];
|
|
13094
13363
|
break;
|
|
13095
13364
|
case 3:
|
|
13096
|
-
this.scene.
|
|
13097
|
-
|
|
13365
|
+
this.scene.clipPlaneDepthAziElev = [0, 0, 0];
|
|
13366
|
+
break;
|
|
13367
|
+
case 4:
|
|
13368
|
+
this.scene.clipPlaneDepthAziElev = [0, 180, 0];
|
|
13369
|
+
break;
|
|
13370
|
+
case 5:
|
|
13371
|
+
this.scene.clipPlaneDepthAziElev = [0, 0, -90];
|
|
13372
|
+
break;
|
|
13373
|
+
case 6:
|
|
13374
|
+
this.scene.clipPlaneDepthAziElev = [0, 0, 90];
|
|
13098
13375
|
break;
|
|
13099
13376
|
}
|
|
13100
|
-
this.
|
|
13377
|
+
this.clipPlaneUpdate(this.scene.clipPlaneDepthAziElev);
|
|
13101
13378
|
}
|
|
13102
13379
|
this.lastCalled = now;
|
|
13103
13380
|
} else if (e.code === this.opts.viewModeHotKey) {
|
|
@@ -13147,6 +13424,9 @@ Niivue.prototype.dragOverListener = function(e) {
|
|
|
13147
13424
|
Niivue.prototype.dropListener = async function(e) {
|
|
13148
13425
|
e.stopPropagation();
|
|
13149
13426
|
e.preventDefault();
|
|
13427
|
+
if (!this.opts.dragAndDropEnabled) {
|
|
13428
|
+
return;
|
|
13429
|
+
}
|
|
13150
13430
|
const dt = e.dataTransfer;
|
|
13151
13431
|
const url = dt.getData("text/uri-list");
|
|
13152
13432
|
if (url) {
|
|
@@ -13169,13 +13449,9 @@ Niivue.prototype.getRadiologicalConvention = function() {
|
|
|
13169
13449
|
return this.opts.isRadiologicalConvention;
|
|
13170
13450
|
};
|
|
13171
13451
|
Niivue.prototype.addVolume = function(volume) {
|
|
13172
|
-
if (this.volumes.length > 1) {
|
|
13173
|
-
this.overlays.push(volume);
|
|
13174
|
-
} else {
|
|
13175
|
-
this.back = volume;
|
|
13176
|
-
}
|
|
13177
13452
|
this.volumes.push(volume);
|
|
13178
|
-
this.
|
|
13453
|
+
let idx = this.volumes.length === 1 ? 1 : this.volumes.length - 1;
|
|
13454
|
+
this.setVolume(volume, idx);
|
|
13179
13455
|
};
|
|
13180
13456
|
Niivue.prototype.getVolumeIndexByID = function(id) {
|
|
13181
13457
|
let n = this.volumes.length;
|
|
@@ -13268,19 +13544,19 @@ Niivue.prototype.sph2cartDeg = function sph2cartDeg(azimuth, elevation) {
|
|
|
13268
13544
|
Math.cos(Phi) * Math.sin(Theta),
|
|
13269
13545
|
Math.sin(Phi)
|
|
13270
13546
|
];
|
|
13271
|
-
let
|
|
13272
|
-
if (
|
|
13547
|
+
let len2 = Math.sqrt(ret[0] * ret[0] + ret[1] * ret[1] + ret[2] * ret[2]);
|
|
13548
|
+
if (len2 <= 0)
|
|
13273
13549
|
return ret;
|
|
13274
|
-
ret[0] /=
|
|
13275
|
-
ret[1] /=
|
|
13276
|
-
ret[2] /=
|
|
13550
|
+
ret[0] /= len2;
|
|
13551
|
+
ret[1] /= len2;
|
|
13552
|
+
ret[2] /= len2;
|
|
13277
13553
|
return ret;
|
|
13278
13554
|
};
|
|
13279
|
-
Niivue.prototype.clipPlaneUpdate = function(
|
|
13555
|
+
Niivue.prototype.clipPlaneUpdate = function(depthAzimuthElevation) {
|
|
13280
13556
|
if (this.sliceType != this.sliceTypeRender)
|
|
13281
13557
|
return;
|
|
13282
|
-
let v = this.sph2cartDeg(
|
|
13283
|
-
this.scene.clipPlane = [v[0], v[1], v[2],
|
|
13558
|
+
let v = this.sph2cartDeg(depthAzimuthElevation[1] + 180, depthAzimuthElevation[2]);
|
|
13559
|
+
this.scene.clipPlane = [v[0], v[1], v[2], depthAzimuthElevation[0]];
|
|
13284
13560
|
this.drawScene();
|
|
13285
13561
|
};
|
|
13286
13562
|
Niivue.prototype.setCrosshairColor = function(color) {
|
|
@@ -13301,7 +13577,6 @@ Niivue.prototype.setSliceType = function(st) {
|
|
|
13301
13577
|
Niivue.prototype.setOpacity = function(volIdx, newOpacity) {
|
|
13302
13578
|
this.volumes[volIdx].opacity = newOpacity;
|
|
13303
13579
|
if (volIdx === 0) {
|
|
13304
|
-
this.backOpacity = newOpacity;
|
|
13305
13580
|
this.drawScene();
|
|
13306
13581
|
return;
|
|
13307
13582
|
}
|
|
@@ -13344,7 +13619,7 @@ Niivue.prototype.overlayRGBA = function(volume) {
|
|
|
13344
13619
|
return imgRGBA;
|
|
13345
13620
|
};
|
|
13346
13621
|
Niivue.prototype.vox2mm = function(XYZ, mtx) {
|
|
13347
|
-
let sform = clone(mtx);
|
|
13622
|
+
let sform = clone$1(mtx);
|
|
13348
13623
|
transpose(sform, sform);
|
|
13349
13624
|
let pos = fromValues(XYZ[0], XYZ[1], XYZ[2], 1);
|
|
13350
13625
|
transformMat4(pos, pos, sform);
|
|
@@ -13360,7 +13635,7 @@ Niivue.prototype.loadVolumes = async function(volumeList) {
|
|
|
13360
13635
|
this.loadingText = "loading...";
|
|
13361
13636
|
this.drawScene();
|
|
13362
13637
|
} else {
|
|
13363
|
-
this.loadingText =
|
|
13638
|
+
this.loadingText = this.opts.loadingText;
|
|
13364
13639
|
}
|
|
13365
13640
|
});
|
|
13366
13641
|
if (!this.initialized)
|
|
@@ -13368,8 +13643,9 @@ Niivue.prototype.loadVolumes = async function(volumeList) {
|
|
|
13368
13643
|
this.volumes = [];
|
|
13369
13644
|
this.gl.clearColor(0, 0, 0, 1);
|
|
13370
13645
|
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
|
13371
|
-
this.scene.loading$.next(
|
|
13646
|
+
this.scene.loading$.next(false);
|
|
13372
13647
|
for (let i = 0; i < volumeList.length; i++) {
|
|
13648
|
+
this.scene.loading$.next(true);
|
|
13373
13649
|
let volume = await NVImage.loadFromUrl(volumeList[i].url, volumeList[i].name, volumeList[i].colorMap, volumeList[i].opacity, this.opts.trustCalMinMax);
|
|
13374
13650
|
this.scene.loading$.next(false);
|
|
13375
13651
|
this.volumes.push(volume);
|
|
@@ -13524,11 +13800,6 @@ Niivue.prototype.init = async function() {
|
|
|
13524
13800
|
this.gl.bufferData(this.gl.ARRAY_BUFFER, clipPlaneVertices, this.gl.STATIC_DRAW);
|
|
13525
13801
|
this.gl.enableVertexAttribArray(0);
|
|
13526
13802
|
this.gl.vertexAttribPointer(0, 3, this.gl.FLOAT, false, 0, 0);
|
|
13527
|
-
this.clipPlaneObject3D = new NiivueObject3D(this.CLIP_PLANE_ID, vertexBuffer, this.gl.TRIANGLES, 6);
|
|
13528
|
-
this.clipPlaneObject3D.position = [0, 0, this.DISTANCE_FROM_CAMERA];
|
|
13529
|
-
this.clipPlaneObject3D.isVisible = false;
|
|
13530
|
-
this.clipPlaneObject3D.rotationRadians = Math.PI / 2;
|
|
13531
|
-
this.objectsToRender3D.push(this.clipPlaneObject3D);
|
|
13532
13803
|
let cubeStrip = [
|
|
13533
13804
|
0,
|
|
13534
13805
|
1,
|
|
@@ -13584,7 +13855,7 @@ Niivue.prototype.init = async function() {
|
|
|
13584
13855
|
this.volumeObject3D = new NiivueObject3D(this.VOLUME_ID, vbo, this.gl.TRIANGLE_STRIP, 14);
|
|
13585
13856
|
this.volumeObject3D.glFlags = this.volumeObject3D.BLEND | this.volumeObject3D.CULL_FACE | this.volumeObject3D.CULL_FRONT;
|
|
13586
13857
|
this.volumeObject3D.position = [0, 0, this.DISTANCE_FROM_CAMERA];
|
|
13587
|
-
let pickingShader = new Shader(this.gl,
|
|
13858
|
+
let pickingShader = new Shader(this.gl, vertRenderShader, fragVolumePickingShader);
|
|
13588
13859
|
pickingShader.use(this.gl);
|
|
13589
13860
|
this.gl.uniform1i(pickingShader.uniforms["volume"], 0);
|
|
13590
13861
|
this.gl.uniform1i(pickingShader.uniforms["colormap"], 1);
|
|
@@ -13605,8 +13876,10 @@ Niivue.prototype.init = async function() {
|
|
|
13605
13876
|
this.gl.uniform1i(this.renderShader.uniforms["volume"], 0);
|
|
13606
13877
|
this.gl.uniform1i(this.renderShader.uniforms["colormap"], 1);
|
|
13607
13878
|
this.gl.uniform1i(this.renderShader.uniforms["overlay"], 2);
|
|
13879
|
+
this.pickingShader = new Shader(this.gl, vertRenderShader, fragVolumePickingShader);
|
|
13608
13880
|
let volumeRenderShader = new NiivueShader3D(this.renderShader);
|
|
13609
13881
|
volumeRenderShader.mvpUniformName = "mvpMtx";
|
|
13882
|
+
volumeRenderShader.matRASUniformName = "matRAS";
|
|
13610
13883
|
volumeRenderShader.rayDirUniformName = "rayDir";
|
|
13611
13884
|
volumeRenderShader.clipPlaneUniformName = "clipPlane";
|
|
13612
13885
|
this.volumeObject3D.renderShaders.push(volumeRenderShader);
|
|
@@ -13614,17 +13887,17 @@ Niivue.prototype.init = async function() {
|
|
|
13614
13887
|
this.colorbarShader.use(this.gl);
|
|
13615
13888
|
this.gl.uniform1i(this.colorbarShader.uniforms["colormap"], 1);
|
|
13616
13889
|
this.passThroughShader = new Shader(this.gl, vertPassThroughShader, fragPassThroughShader);
|
|
13890
|
+
this.orientShaderAtlasU = new Shader(this.gl, vertOrientShader, fragOrientShaderU.concat(fragOrientShaderAtlas));
|
|
13617
13891
|
this.orientShaderU = new Shader(this.gl, vertOrientShader, fragOrientShaderU.concat(fragOrientShader));
|
|
13618
13892
|
this.orientShaderI = new Shader(this.gl, vertOrientShader, fragOrientShaderI.concat(fragOrientShader));
|
|
13619
13893
|
this.orientShaderF = new Shader(this.gl, vertOrientShader, fragOrientShaderF.concat(fragOrientShader));
|
|
13620
13894
|
this.orientShaderRGBU = new Shader(this.gl, vertOrientShader, fragOrientShaderU.concat(fragRGBOrientShader));
|
|
13621
|
-
this.pickingSurfaceShader = new Shader(this.gl,
|
|
13895
|
+
this.pickingSurfaceShader = new Shader(this.gl, vertRenderShader, fragDepthPickingShader);
|
|
13622
13896
|
this.surfaceShader = new Shader(this.gl, vertSurfaceShader, fragSurfaceShader);
|
|
13623
13897
|
this.surfaceShader.use(this.gl);
|
|
13624
13898
|
this.gl.uniform4fv(this.surfaceShader.uniforms["surfaceColor"], this.opts.clipPlaneColor);
|
|
13625
13899
|
let clipPlaneShader = new NiivueShader3D(this.surfaceShader);
|
|
13626
13900
|
clipPlaneShader.mvpUniformName = "mvpMtx";
|
|
13627
|
-
this.clipPlaneObject3D.renderShaders.push(clipPlaneShader);
|
|
13628
13901
|
await this.initText();
|
|
13629
13902
|
this.updateGLVolume();
|
|
13630
13903
|
this.initialized = true;
|
|
@@ -13649,7 +13922,9 @@ Niivue.prototype.refreshLayers = function(overlayItem, layer, numLayers) {
|
|
|
13649
13922
|
let img = overlayItem.img;
|
|
13650
13923
|
let opacity = overlayItem.opacity;
|
|
13651
13924
|
let outTexture = null;
|
|
13652
|
-
|
|
13925
|
+
if (this.crosshairs3D !== null)
|
|
13926
|
+
this.crosshairs3D.mm[0] = NaN;
|
|
13927
|
+
let mtx = clone$1(overlayItem.toRAS);
|
|
13653
13928
|
if (layer === 0) {
|
|
13654
13929
|
this.volumeObject3D = overlayItem.toNiivueObject3D(this.VOLUME_ID, this.gl);
|
|
13655
13930
|
this.volumeObject3D.glFlags = this.volumeObject3D.CULL_FACE;
|
|
@@ -13667,11 +13942,12 @@ Niivue.prototype.refreshLayers = function(overlayItem, layer, numLayers) {
|
|
|
13667
13942
|
this.renderShader.use(this.gl);
|
|
13668
13943
|
this.gl.uniform3fv(this.renderShader.uniforms["texVox"], vox2);
|
|
13669
13944
|
this.gl.uniform3fv(this.renderShader.uniforms["volScale"], volScale2);
|
|
13670
|
-
let volumeRenderShader =
|
|
13945
|
+
let volumeRenderShader = this.renderShader;
|
|
13946
|
+
let pickingShader = this.pickingShader;
|
|
13671
13947
|
volumeRenderShader.mvpUniformName = "mvpMtx";
|
|
13948
|
+
volumeRenderShader.matRASUniformName = "matRAS";
|
|
13672
13949
|
volumeRenderShader.rayDirUniformName = "rayDir";
|
|
13673
13950
|
volumeRenderShader.clipPlaneUniformName = "clipPlane";
|
|
13674
|
-
let pickingShader = new Shader(this.gl, vertVolumePickingShader, fragVolumePickingShader);
|
|
13675
13951
|
pickingShader.use(this.gl);
|
|
13676
13952
|
this.gl.uniform1i(pickingShader.uniforms["volume"], 0);
|
|
13677
13953
|
this.gl.uniform1i(pickingShader.uniforms["colormap"], 1);
|
|
@@ -13680,11 +13956,13 @@ Niivue.prototype.refreshLayers = function(overlayItem, layer, numLayers) {
|
|
|
13680
13956
|
pickingShader.rayDirUniformName = "rayDir";
|
|
13681
13957
|
pickingShader.clipPlaneUniformName = "clipPlane";
|
|
13682
13958
|
this.gl.uniform3fv(pickingShader.uniforms["volScale"], volScale2);
|
|
13683
|
-
this.volumeObject3D.pickingShader
|
|
13959
|
+
if (this.volumeObject3D.pickingShader === null)
|
|
13960
|
+
this.volumeObject3D.pickingShader = pickingShader;
|
|
13684
13961
|
this.volumeObject3D.renderShaders.push(volumeRenderShader);
|
|
13962
|
+
log.debug(this.volumeObject3D);
|
|
13685
13963
|
} else {
|
|
13686
13964
|
if (this.back.dims === void 0)
|
|
13687
|
-
|
|
13965
|
+
log.error("Fatal error: Unable to render overlay: background dimensions not defined!");
|
|
13688
13966
|
let f000 = this.mm2frac(overlayItem.mm000);
|
|
13689
13967
|
let f100 = this.mm2frac(overlayItem.mm100);
|
|
13690
13968
|
let f010 = this.mm2frac(overlayItem.mm010);
|
|
@@ -13716,6 +13994,8 @@ Niivue.prototype.refreshLayers = function(overlayItem, layer, numLayers) {
|
|
|
13716
13994
|
this.gl.pixelStorei(this.gl.UNPACK_ALIGNMENT, 1);
|
|
13717
13995
|
let orientShader = this.orientShaderU;
|
|
13718
13996
|
if (hdr.datatypeCode === 2) {
|
|
13997
|
+
if (hdr.intent_code === 1002)
|
|
13998
|
+
orientShader = this.orientShaderAtlasU;
|
|
13719
13999
|
this.gl.texStorage3D(this.gl.TEXTURE_3D, 1, this.gl.R8UI, hdr.dims[1], hdr.dims[2], hdr.dims[3]);
|
|
13720
14000
|
this.gl.texSubImage3D(this.gl.TEXTURE_3D, 0, 0, 0, 0, hdr.dims[1], hdr.dims[2], hdr.dims[3], this.gl.RED_INTEGER, this.gl.UNSIGNED_BYTE, img);
|
|
13721
14001
|
} else if (hdr.datatypeCode === 4) {
|
|
@@ -13781,6 +14061,16 @@ Niivue.prototype.refreshLayers = function(overlayItem, layer, numLayers) {
|
|
|
13781
14061
|
this.gl.uniform1f(orientShader.uniforms["scl_slope"], hdr.scl_slope);
|
|
13782
14062
|
this.gl.uniform1f(orientShader.uniforms["opacity"], opacity);
|
|
13783
14063
|
this.gl.uniformMatrix4fv(orientShader.uniforms["mtx"], false, mtx);
|
|
14064
|
+
if (hdr.intent_code === 1002) {
|
|
14065
|
+
let x = 1 / this.back.dims[1];
|
|
14066
|
+
if (!this.opts.isAtlasOutline)
|
|
14067
|
+
x = -x;
|
|
14068
|
+
this.gl.uniform3fv(orientShader.uniforms["xyzFrac"], [
|
|
14069
|
+
x,
|
|
14070
|
+
1 / this.back.dims[2],
|
|
14071
|
+
1 / this.back.dims[3]
|
|
14072
|
+
]);
|
|
14073
|
+
}
|
|
13784
14074
|
log.debug("back dims: ", this.back.dims);
|
|
13785
14075
|
for (let i = 0; i < this.back.dims[3]; i++) {
|
|
13786
14076
|
let coordZ = 1 / this.back.dims[3] * (i + 0.5);
|
|
@@ -13799,12 +14089,15 @@ Niivue.prototype.refreshLayers = function(overlayItem, layer, numLayers) {
|
|
|
13799
14089
|
let vox = slicescl.vox;
|
|
13800
14090
|
let volScale = slicescl.volScale;
|
|
13801
14091
|
this.gl.uniform1f(this.renderShader.uniforms["overlays"], this.overlays);
|
|
14092
|
+
this.gl.uniform4fv(this.renderShader.uniforms["clipPlaneColor"], this.opts.clipPlaneColor);
|
|
13802
14093
|
this.gl.uniform1f(this.renderShader.uniforms["backOpacity"], this.volumes[0].opacity);
|
|
13803
14094
|
this.gl.uniform4fv(this.renderShader.uniforms["clipPlane"], this.scene.clipPlane);
|
|
13804
14095
|
this.gl.uniform3fv(this.renderShader.uniforms["texVox"], vox);
|
|
13805
14096
|
this.gl.uniform3fv(this.renderShader.uniforms["volScale"], volScale);
|
|
13806
14097
|
this.volumeObject3D.pickingShader.use(this.gl);
|
|
14098
|
+
this.gl.uniform1f(this.pickingShader.uniforms["overlays"], this.overlays);
|
|
13807
14099
|
this.gl.uniform3fv(this.volumeObject3D.pickingShader.uniforms["texVox"], vox);
|
|
14100
|
+
this.updateInterpolation(layer);
|
|
13808
14101
|
};
|
|
13809
14102
|
Niivue.prototype.colorMaps = function(sort = true) {
|
|
13810
14103
|
let cm = [];
|
|
@@ -13906,6 +14199,18 @@ Niivue.prototype.mouseClick = function(x, y, posChange = 0, isDelta = true) {
|
|
|
13906
14199
|
if (this.sliceType === this.sliceTypeRender) {
|
|
13907
14200
|
if (posChange === 0)
|
|
13908
14201
|
return;
|
|
14202
|
+
if (this.scene.clipPlaneDepthAziElev[0] < 1.8) {
|
|
14203
|
+
let depthAziElev = this.scene.clipPlaneDepthAziElev.slice();
|
|
14204
|
+
if (posChange > 0)
|
|
14205
|
+
depthAziElev[0] = Math.min(1.5, depthAziElev[0] + 0.025);
|
|
14206
|
+
if (posChange < 0)
|
|
14207
|
+
depthAziElev[0] = Math.max(-1.5, depthAziElev[0] - 0.025);
|
|
14208
|
+
if (depthAziElev[0] !== this.scene.clipPlaneDepthAziElev[0]) {
|
|
14209
|
+
this.scene.clipPlaneDepthAziElev = depthAziElev;
|
|
14210
|
+
return this.clipPlaneUpdate(this.scene.clipPlaneDepthAziElev);
|
|
14211
|
+
}
|
|
14212
|
+
return;
|
|
14213
|
+
}
|
|
13909
14214
|
if (posChange > 0)
|
|
13910
14215
|
this.volScaleMultiplier = Math.min(2, this.volScaleMultiplier * 1.1);
|
|
13911
14216
|
if (posChange < 0)
|
|
@@ -14051,7 +14356,7 @@ Niivue.prototype.drawText = function(xy, str, scale = 1) {
|
|
|
14051
14356
|
if (this.opts.textHeight <= 0)
|
|
14052
14357
|
return;
|
|
14053
14358
|
this.fontShader.use(this.gl);
|
|
14054
|
-
let size = this.opts.textHeight * this.gl.canvas.height * scale;
|
|
14359
|
+
let size = this.opts.textHeight * Math.min(this.gl.canvas.height, this.gl.canvas.width) * scale;
|
|
14055
14360
|
this.gl.enable(this.gl.BLEND);
|
|
14056
14361
|
this.gl.uniform2f(this.fontShader.uniforms["canvasWidthHeight"], this.gl.canvas.width, this.gl.canvas.height);
|
|
14057
14362
|
this.gl.uniform4fv(this.fontShader.uniforms["fontColor"], this.opts.crosshairColor);
|
|
@@ -14075,6 +14380,33 @@ Niivue.prototype.drawTextBelow = function(xy, str, scale = 1) {
|
|
|
14075
14380
|
xy[0] -= 0.5 * this.textWidth(size, str);
|
|
14076
14381
|
this.drawText(xy, str, scale);
|
|
14077
14382
|
};
|
|
14383
|
+
Niivue.prototype.updateInterpolation = function(layer) {
|
|
14384
|
+
let interp = this.gl.LINEAR;
|
|
14385
|
+
if (this.opts.isNearestInterpolation)
|
|
14386
|
+
interp = this.gl.NEAREST;
|
|
14387
|
+
if (layer === 0)
|
|
14388
|
+
this.gl.activeTexture(this.gl.TEXTURE0);
|
|
14389
|
+
else
|
|
14390
|
+
this.gl.activeTexture(this.gl.TEXTURE2);
|
|
14391
|
+
this.gl.texParameteri(this.gl.TEXTURE_3D, this.gl.TEXTURE_MIN_FILTER, interp);
|
|
14392
|
+
this.gl.texParameteri(this.gl.TEXTURE_3D, this.gl.TEXTURE_MAG_FILTER, interp);
|
|
14393
|
+
this.volumes.length;
|
|
14394
|
+
};
|
|
14395
|
+
Niivue.prototype.setAtlasOutline = function(isOutline) {
|
|
14396
|
+
this.opts.isAtlasOutline = isOutline;
|
|
14397
|
+
this.updateGLVolume();
|
|
14398
|
+
this.drawScene();
|
|
14399
|
+
};
|
|
14400
|
+
Niivue.prototype.setInterpolation = function(isNearest) {
|
|
14401
|
+
this.opts.isNearestInterpolation = isNearest;
|
|
14402
|
+
let numLayers = this.volumes.length;
|
|
14403
|
+
if (numLayers < 1)
|
|
14404
|
+
return;
|
|
14405
|
+
this.updateInterpolation(0);
|
|
14406
|
+
if (numLayers > 1)
|
|
14407
|
+
this.updateInterpolation(1);
|
|
14408
|
+
this.drawScene();
|
|
14409
|
+
};
|
|
14078
14410
|
Niivue.prototype.draw2D = function(leftTopWidthHeight, axCorSag) {
|
|
14079
14411
|
this.gl.cullFace(this.gl.FRONT);
|
|
14080
14412
|
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.cuboidVertexBuffer);
|
|
@@ -14098,7 +14430,7 @@ Niivue.prototype.draw2D = function(leftTopWidthHeight, axCorSag) {
|
|
|
14098
14430
|
];
|
|
14099
14431
|
let isMirrorLR = this.opts.isRadiologicalConvention && axCorSag < this.sliceTypeSagittal;
|
|
14100
14432
|
this.sliceShader.use(this.gl);
|
|
14101
|
-
this.gl.uniform1f(this.sliceShader.uniforms["opacity"], this.
|
|
14433
|
+
this.gl.uniform1f(this.sliceShader.uniforms["opacity"], this.volumes[0].opacity);
|
|
14102
14434
|
this.gl.uniform1i(this.sliceShader.uniforms["axCorSag"], axCorSag);
|
|
14103
14435
|
this.gl.uniform1f(this.sliceShader.uniforms["slice"], crossXYZ[2]);
|
|
14104
14436
|
this.gl.uniform2fv(this.sliceShader.uniforms["canvasWidthHeight"], [
|
|
@@ -14158,7 +14490,7 @@ Niivue.prototype.calculateMvpMatrix = function(object3D) {
|
|
|
14158
14490
|
}
|
|
14159
14491
|
let whratio = this.gl.canvas.clientWidth / this.gl.canvas.clientHeight;
|
|
14160
14492
|
let projectionMatrix = create$2();
|
|
14161
|
-
let scale = 0.7 *
|
|
14493
|
+
let scale = 0.7 * this.volumeObject3D.furthestVertexFromOrigin * 1 / this.volScaleMultiplier;
|
|
14162
14494
|
if (whratio < 1)
|
|
14163
14495
|
ortho(projectionMatrix, -scale, scale, -scale / whratio, scale / whratio, 0.01, scale * 8);
|
|
14164
14496
|
else
|
|
@@ -14167,20 +14499,34 @@ Niivue.prototype.calculateMvpMatrix = function(object3D) {
|
|
|
14167
14499
|
modelMatrix[0] = -1;
|
|
14168
14500
|
let translateVec3 = fromValues$1(0, 0, -scale * 1.8);
|
|
14169
14501
|
translate(modelMatrix, modelMatrix, translateVec3);
|
|
14502
|
+
translate(modelMatrix, modelMatrix, this.volumeObject3D.position);
|
|
14170
14503
|
rotateX(modelMatrix, modelMatrix, deg2rad(270 - this.scene.renderElevation));
|
|
14171
14504
|
rotateZ(modelMatrix, modelMatrix, deg2rad(this.scene.renderAzimuth - 180));
|
|
14505
|
+
translate(modelMatrix, modelMatrix, this.volumeObject3D.originNegate);
|
|
14172
14506
|
let modelViewProjectionMatrix = create$2();
|
|
14173
14507
|
multiply$1(modelViewProjectionMatrix, projectionMatrix, modelMatrix);
|
|
14174
14508
|
return modelViewProjectionMatrix;
|
|
14175
14509
|
};
|
|
14176
|
-
Niivue.prototype.calculateRayDirection = function(
|
|
14510
|
+
Niivue.prototype.calculateRayDirection = function() {
|
|
14511
|
+
function deg2rad(deg) {
|
|
14512
|
+
return deg * (Math.PI / 180);
|
|
14513
|
+
}
|
|
14514
|
+
const modelMatrix = create$2();
|
|
14515
|
+
modelMatrix[0] = -1;
|
|
14516
|
+
rotateX(modelMatrix, modelMatrix, deg2rad(270 - this.scene.renderElevation));
|
|
14517
|
+
rotateZ(modelMatrix, modelMatrix, deg2rad(this.scene.renderAzimuth - 180));
|
|
14518
|
+
let oblique = clone$1(this.back.obliqueRAS);
|
|
14519
|
+
multiply$1(modelMatrix, modelMatrix, oblique);
|
|
14520
|
+
let projectionMatrix = fromValues$2(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1);
|
|
14521
|
+
let mvpMatrix = create$2();
|
|
14522
|
+
multiply$1(mvpMatrix, projectionMatrix, modelMatrix);
|
|
14177
14523
|
var inv = create$2();
|
|
14178
14524
|
invert(inv, mvpMatrix);
|
|
14179
14525
|
var rayDir4 = fromValues(0, 0, -1, 1);
|
|
14180
14526
|
transformMat4(rayDir4, rayDir4, inv);
|
|
14181
14527
|
let rayDir = fromValues$1(rayDir4[0], rayDir4[1], rayDir4[2]);
|
|
14182
14528
|
normalize(rayDir, rayDir);
|
|
14183
|
-
const tiny =
|
|
14529
|
+
const tiny = 5e-5;
|
|
14184
14530
|
if (Math.abs(rayDir[0]) < tiny)
|
|
14185
14531
|
rayDir[0] = tiny;
|
|
14186
14532
|
if (Math.abs(rayDir[1]) < tiny)
|
|
@@ -14192,57 +14538,84 @@ Niivue.prototype.calculateRayDirection = function(mvpMatrix) {
|
|
|
14192
14538
|
Niivue.prototype.draw3D = function() {
|
|
14193
14539
|
this.gl.viewport(0, 0, this.gl.canvas.width, this.gl.canvas.height);
|
|
14194
14540
|
this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
|
|
14195
|
-
|
|
14196
|
-
|
|
14197
|
-
|
|
14198
|
-
|
|
14199
|
-
|
|
14200
|
-
|
|
14201
|
-
|
|
14202
|
-
|
|
14203
|
-
|
|
14204
|
-
|
|
14205
|
-
|
|
14541
|
+
const mvpMatrix = this.calculateMvpMatrix(this.volumeObject3D);
|
|
14542
|
+
const rayDir = this.calculateRayDirection();
|
|
14543
|
+
if (this.scene.mouseDepthPicker) {
|
|
14544
|
+
this.scene.mouseDepthPicker = false;
|
|
14545
|
+
for (const object3D of this.objectsToRender3D) {
|
|
14546
|
+
if (!object3D.isVisible || !object3D.isPickable) {
|
|
14547
|
+
continue;
|
|
14548
|
+
}
|
|
14549
|
+
let pickingShader = object3D.pickingShader ? object3D.pickingShader : this.pickingSurfaceShader;
|
|
14550
|
+
pickingShader.use(this.gl);
|
|
14551
|
+
if (object3D.glFlags & object3D.CULL_FACE) {
|
|
14552
|
+
this.gl.enable(this.gl.CULL_FACE);
|
|
14553
|
+
if (object3D.glFlags & object3D.CULL_FRONT) {
|
|
14554
|
+
this.gl.cullFace(this.gl.FRONT);
|
|
14555
|
+
} else {
|
|
14556
|
+
this.gl.cullFace(this.gl.FRONT);
|
|
14557
|
+
}
|
|
14206
14558
|
} else {
|
|
14207
|
-
this.gl.
|
|
14559
|
+
this.gl.disable(this.gl.CULL_FACE);
|
|
14208
14560
|
}
|
|
14209
|
-
|
|
14210
|
-
|
|
14211
|
-
|
|
14212
|
-
|
|
14213
|
-
|
|
14214
|
-
|
|
14215
|
-
|
|
14216
|
-
|
|
14217
|
-
|
|
14218
|
-
|
|
14219
|
-
this.gl.
|
|
14561
|
+
this.gl.uniformMatrix4fv(pickingShader.uniforms["mvpMtx"], false, mvpMatrix);
|
|
14562
|
+
if (pickingShader.rayDirUniformName) {
|
|
14563
|
+
let rayDir2 = this.calculateRayDirection();
|
|
14564
|
+
this.gl.uniform3fv(pickingShader.uniforms[pickingShader.rayDirUniformName], rayDir2);
|
|
14565
|
+
}
|
|
14566
|
+
if (pickingShader.clipPlaneUniformName) {
|
|
14567
|
+
this.gl.uniform4fv(pickingShader.uniforms["clipPlane"], this.scene.clipPlane);
|
|
14568
|
+
}
|
|
14569
|
+
this.gl.uniform1i(pickingShader.uniforms["id"], object3D.id);
|
|
14570
|
+
this.gl.enableVertexAttribArray(0);
|
|
14571
|
+
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, object3D.vertexBuffer);
|
|
14572
|
+
this.gl.vertexAttribPointer(0, 3, this.gl.FLOAT, false, 0, 0);
|
|
14573
|
+
if (object3D.textureCoordinateBuffer) {
|
|
14574
|
+
this.gl.enableVertexAttribArray(1);
|
|
14575
|
+
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, object3D.textureCoordinateBuffer);
|
|
14576
|
+
this.gl.vertexAttribPointer(1, 3, this.gl.FLOAT, false, 0, 0);
|
|
14577
|
+
} else {
|
|
14578
|
+
this.gl.disableVertexAttribArray(1);
|
|
14579
|
+
}
|
|
14580
|
+
if (object3D.indexBuffer) {
|
|
14581
|
+
this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, object3D.indexBuffer);
|
|
14582
|
+
}
|
|
14583
|
+
if (object3D.glFlags & object3D.CULL_FACE) {
|
|
14584
|
+
this.gl.enable(this.gl.CULL_FACE);
|
|
14585
|
+
if (object3D.glFlags & object3D.CULL_FRONT) {
|
|
14586
|
+
this.gl.cullFace(this.gl.FRONT);
|
|
14587
|
+
} else {
|
|
14588
|
+
this.gl.cullFace(this.gl.FRONT);
|
|
14589
|
+
}
|
|
14590
|
+
} else {
|
|
14591
|
+
this.gl.disable(this.gl.CULL_FACE);
|
|
14592
|
+
}
|
|
14593
|
+
if (object3D.mode === this.gl.TRIANGLE_STRIP) {
|
|
14594
|
+
continue;
|
|
14595
|
+
}
|
|
14596
|
+
this.gl.drawElements(object3D.mode, object3D.indexCount, this.gl.UNSIGNED_SHORT, 0);
|
|
14220
14597
|
}
|
|
14221
|
-
this.gl.
|
|
14598
|
+
const pixelX = this.mousePos[0] * this.gl.canvas.width / this.gl.canvas.clientWidth;
|
|
14599
|
+
const pixelY = this.gl.canvas.height - this.mousePos[1] * this.gl.canvas.height / this.gl.canvas.clientHeight - 1;
|
|
14600
|
+
const rgbaPixel = new Uint8Array(4);
|
|
14601
|
+
this.gl.readPixels(pixelX, pixelY, 1, 1, this.gl.RGBA, this.gl.UNSIGNED_BYTE, rgbaPixel);
|
|
14222
14602
|
this.gl.enableVertexAttribArray(0);
|
|
14223
|
-
this.gl.bindBuffer(this.gl.ARRAY_BUFFER,
|
|
14603
|
+
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.cuboidVertexBuffer);
|
|
14224
14604
|
this.gl.vertexAttribPointer(0, 3, this.gl.FLOAT, false, 0, 0);
|
|
14225
|
-
|
|
14226
|
-
|
|
14227
|
-
this.
|
|
14228
|
-
this.gl.vertexAttribPointer(1, 3, this.gl.FLOAT, false, 0, 0);
|
|
14605
|
+
this.selectedObjectId = rgbaPixel[3];
|
|
14606
|
+
if (this.selectedObjectId === this.VOLUME_ID) {
|
|
14607
|
+
this.scene.crosshairPos = new Float32Array(rgbaPixel.slice(0, 3)).map((x) => x / 255);
|
|
14229
14608
|
}
|
|
14230
|
-
if (
|
|
14231
|
-
|
|
14609
|
+
if (rgbaPixel[3] === 253) {
|
|
14610
|
+
let clipXYZ = new Float32Array(rgbaPixel.slice(0, 3)).map((x) => x / 255);
|
|
14611
|
+
console.log(this.scene.clipPlaneDepthAziElev[0], "User clicked on the clip plane at " + clipXYZ);
|
|
14612
|
+
this.scene.clipPlaneDepthAziElev[0] = this.scene.clipPlaneDepthAziElev[0] - 0.1;
|
|
14613
|
+
if (this.scene.clipPlaneDepthAziElev[0] <= -0.4)
|
|
14614
|
+
this.scene.clipPlaneDepthAziElev[0] = 0.4;
|
|
14615
|
+
this.clipPlaneUpdate(this.scene.clipPlaneDepthAziElev);
|
|
14232
14616
|
}
|
|
14233
|
-
this.gl.drawElements(object3D.mode, object3D.indexCount, this.gl.UNSIGNED_SHORT, 0);
|
|
14234
|
-
break;
|
|
14235
|
-
}
|
|
14236
|
-
const pixelX = this.mousePos[0] * this.gl.canvas.width / this.gl.canvas.clientWidth;
|
|
14237
|
-
const pixelY = this.gl.canvas.height - this.mousePos[1] * this.gl.canvas.height / this.gl.canvas.clientHeight - 1;
|
|
14238
|
-
const rgbaPixel = new Uint8Array(4);
|
|
14239
|
-
this.gl.readPixels(pixelX, pixelY, 1, 1, this.gl.RGBA, this.gl.UNSIGNED_BYTE, rgbaPixel);
|
|
14240
|
-
this.selectedObjectId = rgbaPixel[3];
|
|
14241
|
-
if (this.selectedObjectId === this.VOLUME_ID) {
|
|
14242
|
-
this.scene.crosshairPos = new Float32Array(rgbaPixel.slice(0, 3)).map((x) => x / 255);
|
|
14243
14617
|
}
|
|
14244
14618
|
this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
|
|
14245
|
-
this.gl.clearColor(0.2, 0, 0, 1);
|
|
14246
14619
|
for (const object3D of this.objectsToRender3D) {
|
|
14247
14620
|
if (!object3D.isVisible) {
|
|
14248
14621
|
continue;
|
|
@@ -14258,7 +14631,7 @@ Niivue.prototype.draw3D = function() {
|
|
|
14258
14631
|
if (object3D.indexBuffer) {
|
|
14259
14632
|
this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, object3D.indexBuffer);
|
|
14260
14633
|
}
|
|
14261
|
-
if (object3D.
|
|
14634
|
+
if (object3D.BLEND) {
|
|
14262
14635
|
this.gl.enable(this.gl.BLEND);
|
|
14263
14636
|
this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA);
|
|
14264
14637
|
} else {
|
|
@@ -14274,12 +14647,13 @@ Niivue.prototype.draw3D = function() {
|
|
|
14274
14647
|
} else {
|
|
14275
14648
|
this.gl.disable(this.gl.CULL_FACE);
|
|
14276
14649
|
}
|
|
14277
|
-
m = this.calculateMvpMatrix(object3D);
|
|
14278
|
-
let rayDir = this.calculateRayDirection(m);
|
|
14279
14650
|
for (const shader of object3D.renderShaders) {
|
|
14280
14651
|
shader.use(this.gl);
|
|
14281
14652
|
if (shader.mvpUniformName) {
|
|
14282
|
-
this.gl.uniformMatrix4fv(shader.uniforms[shader.mvpUniformName], false,
|
|
14653
|
+
this.gl.uniformMatrix4fv(shader.uniforms[shader.mvpUniformName], false, mvpMatrix);
|
|
14654
|
+
}
|
|
14655
|
+
if (shader.matRASUniformName) {
|
|
14656
|
+
this.gl.uniformMatrix4fv(shader.uniforms[shader.matRASUniformName], false, this.back.matRAS);
|
|
14283
14657
|
}
|
|
14284
14658
|
if (shader.rayDirUniformName) {
|
|
14285
14659
|
this.gl.uniform3fv(shader.uniforms[shader.rayDirUniformName], rayDir);
|
|
@@ -14289,12 +14663,76 @@ Niivue.prototype.draw3D = function() {
|
|
|
14289
14663
|
}
|
|
14290
14664
|
this.gl.drawElements(object3D.mode, object3D.indexCount, this.gl.UNSIGNED_SHORT, 0);
|
|
14291
14665
|
}
|
|
14292
|
-
break;
|
|
14293
14666
|
}
|
|
14667
|
+
this.drawCrosshairs3D(true, 1);
|
|
14668
|
+
this.drawCrosshairs3D(false, 0.35);
|
|
14294
14669
|
let posString = "azimuth: " + this.scene.renderAzimuth.toFixed(0) + " elevation: " + this.scene.renderElevation.toFixed(0);
|
|
14295
14670
|
this.sync();
|
|
14296
14671
|
return posString;
|
|
14297
14672
|
};
|
|
14673
|
+
Niivue.prototype.drawCrosshairs3D = function(isDepthTest = true, alpha = 1) {
|
|
14674
|
+
if (!this.opts.show3Dcrosshair) {
|
|
14675
|
+
return;
|
|
14676
|
+
}
|
|
14677
|
+
let gl = this.gl;
|
|
14678
|
+
let mm = this.frac2mm(this.scene.crosshairPos);
|
|
14679
|
+
if (this.crosshairs3D === null || this.crosshairs3D.mm[0] !== mm[0] || this.crosshairs3D.mm[1] !== mm[1] || this.crosshairs3D.mm[2] !== mm[2]) {
|
|
14680
|
+
if (this.crosshairs3D !== null) {
|
|
14681
|
+
gl.deleteBuffer(this.crosshairs3D.indexBuffer);
|
|
14682
|
+
gl.deleteBuffer(this.crosshairs3D.vertexBuffer);
|
|
14683
|
+
}
|
|
14684
|
+
let radius = Math.min(Math.min(this.back.pixDims[1], this.back.pixDims[2]), this.back.pixDims[3]);
|
|
14685
|
+
this.crosshairs3D = NiivueObject3D.generateCrosshairs(this.gl, 1, mm, this.volumeObject3D.extentsMin, this.volumeObject3D.extentsMax, radius);
|
|
14686
|
+
this.crosshairs3D.isPickable = false;
|
|
14687
|
+
this.crosshairs3D.minExtent = this.volumeObject3D.minExtent;
|
|
14688
|
+
this.crosshairs3D.maxExtent = this.volumeObject3D.maxExtent;
|
|
14689
|
+
this.crosshairs3D.mm = mm;
|
|
14690
|
+
this.crosshairs3D.originNegate = this.volumeObject3D.originNegate;
|
|
14691
|
+
this.crosshairs3D.furthestVertexFromOrigin = this.volumeObject3D.furthestVertexFromOrigin;
|
|
14692
|
+
}
|
|
14693
|
+
let crosshairsShader = new NiivueShader3D(this.surfaceShader);
|
|
14694
|
+
crosshairsShader.mvpUniformName = "mvpMtx";
|
|
14695
|
+
this.crosshairs3D.renderShaders.push(crosshairsShader);
|
|
14696
|
+
{
|
|
14697
|
+
const numComponents = 3;
|
|
14698
|
+
const type = gl.FLOAT;
|
|
14699
|
+
const normalize2 = false;
|
|
14700
|
+
const stride = 0;
|
|
14701
|
+
const offset = 0;
|
|
14702
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, this.crosshairs3D.vertexBuffer);
|
|
14703
|
+
gl.vertexAttribPointer(this.surfaceShader.uniforms["pos"], numComponents, type, normalize2, stride, offset);
|
|
14704
|
+
gl.enableVertexAttribArray(this.surfaceShader.uniforms["pos"]);
|
|
14705
|
+
}
|
|
14706
|
+
crosshairsShader.use(this.gl);
|
|
14707
|
+
let m = this.calculateMvpMatrix(this.crosshairs3D);
|
|
14708
|
+
gl.uniformMatrix4fv(crosshairsShader.uniforms["mvpMtx"], false, m);
|
|
14709
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.crosshairs3D.indexBuffer);
|
|
14710
|
+
gl.enable(gl.DEPTH_TEST);
|
|
14711
|
+
let color = [...this.opts.crosshairColor];
|
|
14712
|
+
if (isDepthTest) {
|
|
14713
|
+
gl.disable(gl.BLEND);
|
|
14714
|
+
gl.depthFunc(gl.GREATER);
|
|
14715
|
+
color[3] = alpha;
|
|
14716
|
+
} else {
|
|
14717
|
+
gl.enable(gl.BLEND);
|
|
14718
|
+
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
14719
|
+
gl.depthFunc(gl.ALWAYS);
|
|
14720
|
+
color[3] = alpha;
|
|
14721
|
+
}
|
|
14722
|
+
gl.uniform4fv(crosshairsShader.uniforms["surfaceColor"], color);
|
|
14723
|
+
{
|
|
14724
|
+
const vertexCount = this.crosshairs3D.indexCount;
|
|
14725
|
+
const type = gl.UNSIGNED_SHORT;
|
|
14726
|
+
const offset = 0;
|
|
14727
|
+
gl.drawElements(gl.TRIANGLES, vertexCount, type, offset);
|
|
14728
|
+
}
|
|
14729
|
+
gl.enable(gl.BLEND);
|
|
14730
|
+
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
14731
|
+
gl.depthFunc(gl.ALWAYS);
|
|
14732
|
+
this.gl.enableVertexAttribArray(0);
|
|
14733
|
+
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.cuboidVertexBuffer);
|
|
14734
|
+
this.gl.vertexAttribPointer(0, 3, this.gl.FLOAT, false, 0, 0);
|
|
14735
|
+
};
|
|
14298
14736
|
Niivue.prototype.mm2frac = function(mm, volIdx = 0) {
|
|
14299
14737
|
let mm4 = fromValues(mm[0], mm[1], mm[2], 1);
|
|
14300
14738
|
let d = this.volumes[volIdx].hdr.dims;
|
|
@@ -14304,7 +14742,7 @@ Niivue.prototype.mm2frac = function(mm, volIdx = 0) {
|
|
|
14304
14742
|
}
|
|
14305
14743
|
if (d[1] < 1 || d[2] < 1 || d[3] < 1)
|
|
14306
14744
|
return frac;
|
|
14307
|
-
let sform = clone(this.volumes[volIdx].matRAS);
|
|
14745
|
+
let sform = clone$1(this.volumes[volIdx].matRAS);
|
|
14308
14746
|
transpose(sform, sform);
|
|
14309
14747
|
invert(sform, sform);
|
|
14310
14748
|
transformMat4(mm4, mm4, sform);
|
|
@@ -14331,8 +14769,8 @@ Niivue.prototype.frac2vox = function(frac, volIdx = 0) {
|
|
|
14331
14769
|
};
|
|
14332
14770
|
Niivue.prototype.frac2mm = function(frac, volIdx = 0) {
|
|
14333
14771
|
let pos = fromValues(frac[0], frac[1], frac[2], 1);
|
|
14334
|
-
let dim = fromValues(this.volumes[volIdx].
|
|
14335
|
-
let sform = clone(this.volumes[volIdx].matRAS);
|
|
14772
|
+
let dim = fromValues(this.volumes[volIdx].dimsRAS[1], this.volumes[volIdx].dimsRAS[2], this.volumes[volIdx].dimsRAS[3], 1);
|
|
14773
|
+
let sform = clone$1(this.volumes[volIdx].matRAS);
|
|
14336
14774
|
transpose(sform, sform);
|
|
14337
14775
|
mul(pos, pos, dim);
|
|
14338
14776
|
let shim = fromValues(-0.5, -0.5, -0.5, 0);
|
|
@@ -14410,8 +14848,25 @@ Niivue.prototype.drawScene = function() {
|
|
|
14410
14848
|
this.drawLoadingText(this.loadingText);
|
|
14411
14849
|
return;
|
|
14412
14850
|
}
|
|
14413
|
-
if (this.sliceType === this.sliceTypeRender)
|
|
14851
|
+
if (this.sliceType === this.sliceTypeRender) {
|
|
14852
|
+
if (this.isDragging && this.scene.clipPlaneDepthAziElev[0] < 1.8) {
|
|
14853
|
+
let x = this.dragStart[0] - this.dragEnd[0];
|
|
14854
|
+
let y = this.dragStart[1] - this.dragEnd[1];
|
|
14855
|
+
let depthAziElev = this.dragClipPlaneStartDepthAziElev.slice();
|
|
14856
|
+
depthAziElev[1] -= x;
|
|
14857
|
+
depthAziElev[1] = depthAziElev[1] % 360;
|
|
14858
|
+
depthAziElev[2] += y;
|
|
14859
|
+
if (depthAziElev[2] > 90)
|
|
14860
|
+
depthAziElev[2] = 90;
|
|
14861
|
+
if (depthAziElev[2] < -90)
|
|
14862
|
+
depthAziElev[2] = -90;
|
|
14863
|
+
if (depthAziElev[1] !== this.scene.clipPlaneDepthAziElev[1] || depthAziElev[2] !== this.scene.clipPlaneDepthAziElev[2]) {
|
|
14864
|
+
this.scene.clipPlaneDepthAziElev = depthAziElev;
|
|
14865
|
+
return this.clipPlaneUpdate(this.scene.clipPlaneDepthAziElev);
|
|
14866
|
+
}
|
|
14867
|
+
}
|
|
14414
14868
|
return this.draw3D();
|
|
14869
|
+
}
|
|
14415
14870
|
let { volScale } = this.sliceScale();
|
|
14416
14871
|
this.gl.viewport(0, 0, this.gl.canvas.width, this.gl.canvas.height);
|
|
14417
14872
|
this.numScreenSlices = 0;
|