@ohif/app 3.8.0-beta.80 → 3.8.0-beta.81
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{121.bundle.787f5a848ed632a4d5fc.js → 121.bundle.47f05840a5b3cdf75543.js} +4 -1
- package/dist/{183.bundle.72bf18ad23ee6624986d.js → 183.bundle.a3e238998be71c4b2af8.js} +64 -48
- package/dist/{206.bundle.f957e0d1cdff66dbac69.js → 206.bundle.fcaa081a0d1f68095c31.js} +45 -20
- package/dist/{217.bundle.be1cc412f8e26be87d21.js → 217.bundle.d44bbaa50b6fa563fe15.js} +116 -69
- package/dist/{295.bundle.6f734abf8fa85b1a310d.js → 295.bundle.5ace95771ced62bdcab8.js} +4 -1
- package/dist/{325.bundle.84909a08305556e9f924.js → 325.bundle.fd8e0c18db4708d03a91.js} +4 -8
- package/dist/{335.bundle.c39d4aefe33aecab958f.js → 335.bundle.8400aa5a88697a6b9d53.js} +2 -2
- package/dist/{41.bundle.7c943bb857ed37831905.js → 41.bundle.0905b258a90a7c6437bb.js} +174 -104
- package/dist/{422.bundle.bd6529c536f59807fbee.js → 422.bundle.c6fd037b075dd54f1ba7.js} +9 -25
- package/dist/{433.bundle.4c77c1fe8fc90ac14218.js → 433.bundle.e0018820758f5a86fa7f.js} +61 -7
- package/dist/{448.bundle.deedeff5744e77510734.js → 448.bundle.5e6da31477887bf53016.js} +6 -12
- package/dist/{487.bundle.7890ca42826941ebcd60.js → 487.bundle.89d973049defb3ba6cb7.js} +3 -2
- package/dist/{530.bundle.7c94543955552475c56a.js → 530.bundle.207b38c15c4c01e4db0e.js} +14 -2
- package/dist/{574.bundle.be075ac52fb52b442a8b.js → 574.bundle.d648fea691d6709bf2b4.js} +14 -3
- package/dist/{633.bundle.c1658e76f104cbd14cab.js → 633.bundle.acab89baaa06a299d679.js} +48 -33
- package/dist/{540.bundle.079d43a6717e95c24392.js → 669.bundle.b17e8a621e38d92c653f.js} +95 -87
- package/dist/{699.bundle.4f01772e7ce6637de339.js → 699.bundle.9367d7ef9f7615b2e733.js} +41 -37
- package/dist/{724.bundle.e5794460c391ee9cba2c.js → 724.bundle.55f9f49816de931af91a.js} +1 -1
- package/dist/{862.bundle.c0ee6e1d4d97e1353213.js → 862.bundle.d32ab08e64806b2e964d.js} +4 -1
- package/dist/{94.bundle.c452d9b0645277c2cf4e.js → 94.bundle.f5f2479c214180d05d42.js} +7 -13
- package/dist/app.bundle.css +1 -1
- package/dist/{app.bundle.6c090a2d6d3ccc97a81d.js → app.bundle.ed937512f7d19d61c411.js} +188 -64
- package/dist/index.html +1 -1
- package/dist/{polySeg.bundle.63011312c3c79e717ea9.js → polySeg.bundle.f1a6ece1396dc1385155.js} +1 -1
- package/dist/sw.js +1 -1
- package/package.json +18 -18
- /package/dist/{164.bundle.d4598e491783753a8b6b.js → 164.bundle.fadc7c5d634402c73b5f.js} +0 -0
- /package/dist/{188.bundle.b80554ec7df7dcd435a5.js → 188.bundle.51dc4b37920f45594393.js} +0 -0
- /package/dist/{594.bundle.0b1165661dd638820082.js → 594.bundle.84076375b127b9c7f673.js} +0 -0
- /package/dist/{889.bundle.7858e4b7ca1a2b12b64f.js → 889.bundle.8ef8b723d0163d5d135c.js} +0 -0
- /package/dist/{905.bundle.170908fe660fc6b40649.js → 905.bundle.8a96e1a75b7cfe5ec093.js} +0 -0
- /package/dist/{907.bundle.dee4e30420caf07caea6.js → 907.bundle.5c88ed911bed18582da4.js} +0 -0
- /package/dist/{961.bundle.aaaaaba0ec015a3b85d8.js → 961.bundle.f4e52bc76d3044d05372.js} +0 -0
|
@@ -280,6 +280,7 @@ __webpack_require__.d(geometryLoader_namespaceObject, {
|
|
|
280
280
|
;// CONCATENATED MODULE: ../../../node_modules/@cornerstonejs/core/dist/esm/enums/Events.js
|
|
281
281
|
var Events;
|
|
282
282
|
(function (Events) {
|
|
283
|
+
Events["ERROR_EVENT"] = "CORNERSTONE_ERROR";
|
|
283
284
|
Events["CACHE_SIZE_EXCEEDED"] = "CACHE_SIZE_EXCEEDED";
|
|
284
285
|
Events["IMAGE_LOAD_ERROR"] = "IMAGE_LOAD_ERROR";
|
|
285
286
|
Events["CAMERA_MODIFIED"] = "CORNERSTONE_CAMERA_MODIFIED";
|
|
@@ -12697,11 +12698,6 @@ function vtkOpenGLImageMapper(publicAPI, model) {
|
|
|
12697
12698
|
return;
|
|
12698
12699
|
}
|
|
12699
12700
|
|
|
12700
|
-
if (actualThickness == 0) {
|
|
12701
|
-
gl_FragData[0] = vec4(0.0, 0.0, 1.0, 1.0);
|
|
12702
|
-
return;
|
|
12703
|
-
}
|
|
12704
|
-
|
|
12705
12701
|
for (int i = -actualThickness; i <= actualThickness; i++) {
|
|
12706
12702
|
for (int j = -actualThickness; j <= actualThickness; j++) {
|
|
12707
12703
|
if (i == 0 || j == 0) {
|
|
@@ -14940,7 +14936,7 @@ var vtkVolumeVS = "//VTK::System::Dec\n\n/*=====================================
|
|
|
14940
14936
|
|
|
14941
14937
|
|
|
14942
14938
|
;// CONCATENATED MODULE: ../../../node_modules/@kitware/vtk.js/Rendering/OpenGL/glsl/vtkVolumeFS.glsl.js
|
|
14943
|
-
var vtkVolumeFS = "//VTK::System::Dec\n\n/*=========================================================================\n\n Program: Visualization Toolkit\n Module: vtkVolumeFS.glsl\n\n Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen\n All rights reserved.\n See Copyright.txt or http://www.kitware.com/Copyright.htm for details.\n\n This software is distributed WITHOUT ANY WARRANTY; without even\n the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR\n PURPOSE. See the above copyright notice for more information.\n\n=========================================================================*/\n// Template for the volume mappers fragment shader\n\n// the output of this shader\n//VTK::Output::Dec\n\nvarying vec3 vertexVCVSOutput;\n\n// first declare the settings from the mapper\n// that impact the code paths in here\n\n// always set vtkNumComponents 1,2,3,4\n//VTK::NumComponents\n\n// possibly define vtkTrilinearOn\n//VTK::TrilinearOn\n\n// possibly define UseIndependentComponents\n//VTK::IndependentComponentsOn\n\n// possibly define vtkCustomComponentsColorMix\n//VTK::CustomComponentsColorMixOn\n\n// possibly define any \"proportional\" components\n//VTK::vtkProportionalComponents\n\n// possibly define any components that are forced to nearest interpolation\n//VTK::vtkForceNearestComponents\n\n// Define the blend mode to use\n#define vtkBlendMode //VTK::BlendMode\n\n// Possibly define vtkImageLabelOutlineOn\n//VTK::ImageLabelOutlineOn\n\n#ifdef vtkImageLabelOutlineOn\n\nuniform float outlineOpacity;\nuniform float vpWidth;\nuniform float vpHeight;\nuniform float vpOffsetX;\nuniform float vpOffsetY;\nuniform mat4 PCWCMatrix;\nuniform mat4 vWCtoIDX;\n#endif\n\n// define vtkLightComplexity\n//VTK::LightComplexity\n#if vtkLightComplexity > 0\nuniform float vSpecularPower;\nuniform float vAmbient;\nuniform float vDiffuse;\nuniform float vSpecular;\n//VTK::Light::Dec\n#endif\n\n//VTK::VolumeShadowOn\n//VTK::SurfaceShadowOn\n//VTK::localAmbientOcclusionOn\n//VTK::LAO::Dec\n//VTK::VolumeShadow::Dec\n\n// define vtkComputeNormalFromOpacity\n//VTK::vtkComputeNormalFromOpacity\n\n// possibly define vtkGradientOpacityOn\n//VTK::GradientOpacityOn\n#ifdef vtkGradientOpacityOn\nuniform float goscale0;\nuniform float goshift0;\nuniform float gomin0;\nuniform float gomax0;\n#ifdef UseIndependentComponents\n#if vtkNumComponents > 1\nuniform float goscale1;\nuniform float goshift1;\nuniform float gomin1;\nuniform float gomax1;\n#if vtkNumComponents > 2\nuniform float goscale2;\nuniform float goshift2;\nuniform float gomin2;\nuniform float gomax2;\n#if vtkNumComponents > 3\nuniform float goscale3;\nuniform float goshift3;\nuniform float gomin3;\nuniform float gomax3;\n#endif\n#endif\n#endif\n#endif\n#endif\n\n// if you want to see the raw tiled\n// data in webgl1 uncomment the following line\n// #define debugtile\n\n// camera values\nuniform float camThick;\nuniform float camNear;\nuniform float camFar;\nuniform int cameraParallel;\n\n// values describing the volume geometry\nuniform vec3 vOriginVC;\nuniform vec3 vSpacing;\nuniform ivec3 volumeDimensions; // 3d texture dimensions\nuniform vec3 vPlaneNormal0;\nuniform float vPlaneDistance0;\nuniform vec3 vPlaneNormal1;\nuniform float vPlaneDistance1;\nuniform vec3 vPlaneNormal2;\nuniform float vPlaneDistance2;\nuniform vec3 vPlaneNormal3;\nuniform float vPlaneDistance3;\nuniform vec3 vPlaneNormal4;\nuniform float vPlaneDistance4;\nuniform vec3 vPlaneNormal5;\nuniform float vPlaneDistance5;\n\n//VTK::ClipPlane::Dec\n\n// opacity and color textures\nuniform sampler2D otexture;\nuniform float oshift0;\nuniform float oscale0;\nuniform sampler2D ctexture;\nuniform float cshift0;\nuniform float cscale0;\n\n#if vtkNumComponents >= 2\nuniform float oshift1;\nuniform float oscale1;\nuniform float cshift1;\nuniform float cscale1;\n#endif\n#if vtkNumComponents >= 3\nuniform float oshift2;\nuniform float oscale2;\nuniform float cshift2;\nuniform float cscale2;\n#endif\n#if vtkNumComponents >= 4\nuniform float oshift3;\nuniform float oscale3;\nuniform float cshift3;\nuniform float cscale3;\n#endif\n\n// jitter texture\nuniform sampler2D jtexture;\nuniform sampler2D ttexture;\n\n\n// some 3D texture values\nuniform float sampleDistance;\nuniform vec3 vVCToIJK;\n\n// the heights defined below are the locations\n// for the up to four components of the tfuns\n// the tfuns have a height of 2XnumComps pixels so the\n// values are computed to hit the middle of the two rows\n// for that component\n#ifdef UseIndependentComponents\n#if vtkNumComponents == 1\nuniform float mix0;\n#define height0 0.5\n#endif\n#if vtkNumComponents == 2\nuniform float mix0;\nuniform float mix1;\n#define height0 0.25\n#define height1 0.75\n#endif\n#if vtkNumComponents == 3\nuniform float mix0;\nuniform float mix1;\nuniform float mix2;\n#define height0 0.17\n#define height1 0.5\n#define height2 0.83\n#endif\n#if vtkNumComponents == 4\nuniform float mix0;\nuniform float mix1;\nuniform float mix2;\nuniform float mix3;\n#define height0 0.125\n#define height1 0.375\n#define height2 0.625\n#define height3 0.875\n#endif\n#endif\n\nuniform vec4 ipScalarRangeMin;\nuniform vec4 ipScalarRangeMax;\n\n// declaration for intermixed geometry\n//VTK::ZBuffer::Dec\n\n//=======================================================================\n// global and custom variables (a temporary section before photorealistics rendering module is complete)\nvec3 rayDirVC;\nfloat sampleDistanceISVS;\nfloat sampleDistanceIS;\n\n#define SQRT3 1.7321\n#define INV4PI 0.0796\n#define EPSILON 0.001\n#define PI 3.1415\n#define PI2 9.8696\n\n//=======================================================================\n// Webgl2 specific version of functions\n#if __VERSION__ == 300\n\nuniform highp sampler3D texture1;\n\nvec4 getTextureValue(vec3 pos)\n{\n vec4 tmp = texture(texture1, pos);\n\n #if defined(vtkComponent0ForceNearest) || \\\n defined(vtkComponent1ForceNearest) || \\\n defined(vtkComponent2ForceNearest) || \\\n defined(vtkComponent3ForceNearest)\n vec3 nearestPos = (floor(pos * vec3(volumeDimensions)) + 0.5) / vec3(volumeDimensions);\n vec4 nearestValue = texture(texture1, nearestPos);\n #ifdef vtkComponent0ForceNearest\n tmp[0] = nearestValue[0];\n #endif\n #ifdef vtkComponent1ForceNearest\n tmp[1] = nearestValue[1];\n #endif\n #ifdef vtkComponent2ForceNearest\n tmp[2] = nearestValue[2];\n #endif\n #ifdef vtkComponent3ForceNearest\n tmp[3] = nearestValue[3];\n #endif\n #endif\n\n #ifndef UseIndependentComponents\n #if vtkNumComponents == 1\n tmp.a = tmp.r;\n #endif\n #if vtkNumComponents == 2\n tmp.a = tmp.g;\n #endif\n #if vtkNumComponents == 3\n tmp.a = length(tmp.rgb);\n #endif\n #endif\n\n return tmp;\n}\n\n//=======================================================================\n// WebGL1 specific version of functions\n#else\n\nuniform sampler2D texture1;\n\nuniform float texWidth;\nuniform float texHeight;\nuniform int xreps;\nuniform int xstride;\nuniform int ystride;\n\n// if computing trilinear values from multiple z slices\n#ifdef vtkTrilinearOn\nvec4 getTextureValue(vec3 ijk)\n{\n float zoff = 1.0/float(volumeDimensions.z);\n vec4 val1 = getOneTextureValue(ijk);\n vec4 val2 = getOneTextureValue(vec3(ijk.xy, ijk.z + zoff));\n\n float indexZ = float(volumeDimensions)*ijk.z;\n float zmix = indexZ - floor(indexZ);\n\n return mix(val1, val2, zmix);\n}\n\nvec4 getOneTextureValue(vec3 ijk)\n#else // nearest or fast linear\nvec4 getTextureValue(vec3 ijk)\n#endif\n{\n vec3 tdims = vec3(volumeDimensions);\n\n#ifdef debugtile\n vec2 tpos = vec2(ijk.x, ijk.y);\n vec4 tmp = texture2D(texture1, tpos);\n tmp.a = 1.0;\n\n#else\n int z = int(ijk.z * tdims.z);\n int yz = z / xreps;\n int xz = z - yz*xreps;\n\n int tileWidth = volumeDimensions.x/xstride;\n int tileHeight = volumeDimensions.y/ystride;\n\n xz *= tileWidth;\n yz *= tileHeight;\n\n float ni = float(xz) + (ijk.x*float(tileWidth));\n float nj = float(yz) + (ijk.y*float(tileHeight));\n\n vec2 tpos = vec2(ni/texWidth, nj/texHeight);\n\n vec4 tmp = texture2D(texture1, tpos);\n\n#if vtkNumComponents == 1\n tmp.a = tmp.r;\n#endif\n#if vtkNumComponents == 2\n tmp.g = tmp.a;\n#endif\n#if vtkNumComponents == 3\n tmp.a = length(tmp.rgb);\n#endif\n#endif\n\n return tmp;\n}\n\n// End of Webgl1 specific code\n//=======================================================================\n#endif\n\n//=======================================================================\n// transformation between VC and IS space\n\n// convert vector position from idx to vc\n#if (vtkLightComplexity > 0) || (defined vtkClippingPlanesOn)\nvec3 IStoVC(vec3 posIS){\n vec3 posVC = posIS / vVCToIJK;\n return posVC.x * vPlaneNormal0 +\n posVC.y * vPlaneNormal2 +\n posVC.z * vPlaneNormal4 +\n vOriginVC;\n}\n\n// convert vector position from vc to idx\nvec3 VCtoIS(vec3 posVC){\n posVC = posVC - vOriginVC;\n posVC = vec3(\n dot(posVC, vPlaneNormal0),\n dot(posVC, vPlaneNormal2),\n dot(posVC, vPlaneNormal4));\n return posVC * vVCToIJK;\n}\n#endif\n\n//Rotate vector to view coordinate\n#if (vtkLightComplexity > 0) || (defined vtkGradientOpacityOn)\nvoid rotateToViewCoord(inout vec3 dirIS){\n dirIS.xyz =\n dirIS.x * vPlaneNormal0 +\n dirIS.y * vPlaneNormal2 +\n dirIS.z * vPlaneNormal4;\n}\n\n//Rotate vector to idx coordinate\nvec3 rotateToIDX(vec3 dirVC){\n vec3 dirIS;\n dirIS.xyz = vec3(\n dot(dirVC, vPlaneNormal0),\n dot(dirVC, vPlaneNormal2),\n dot(dirVC, vPlaneNormal4));\n return dirIS;\n}\n#endif\n\n//=======================================================================\n// Given a normal compute the gradient opacity factors\nfloat computeGradientOpacityFactor(\n float normalMag, float goscale, float goshift, float gomin, float gomax)\n{\n return clamp(normalMag * goscale + goshift, gomin, gomax);\n}\n\n//=======================================================================\n// compute the normal and gradient magnitude for a position, uses forward difference\n#if (vtkLightComplexity > 0) || (defined vtkGradientOpacityOn)\n #ifdef vtkClippingPlanesOn\n void adjustClippedVoxelValues(vec3 pos, vec3 texPos[3], inout vec3 g1)\n {\n vec3 g1VC[3];\n for (int i = 0; i < 3; ++i)\n {\n g1VC[i] = IStoVC(texPos[i]);\n }\n vec3 posVC = IStoVC(pos);\n for (int i = 0; i < clip_numPlanes; ++i)\n {\n for (int j = 0; j < 3; ++j)\n {\n if(dot(vec3(vClipPlaneOrigins[i] - g1VC[j].xyz), vClipPlaneNormals[i]) > 0.0)\n {\n g1[j] = 0.0;\n }\n }\n }\n }\n #endif\n\n #ifdef vtkComputeNormalFromOpacity\n vec4 computeDensityNormal(vec3 opacityUCoords[2], float opactityTextureHeight, float gradientOpacity) {\n vec3 opacityG1, opacityG2;\n opacityG1.x = texture2D(otexture, vec2(opacityUCoords[0].x, opactityTextureHeight)).r;\n opacityG1.y = texture2D(otexture, vec2(opacityUCoords[0].y, opactityTextureHeight)).r;\n opacityG1.z = texture2D(otexture, vec2(opacityUCoords[0].z, opactityTextureHeight)).r;\n opacityG2.x = texture2D(otexture, vec2(opacityUCoords[1].x, opactityTextureHeight)).r;\n opacityG2.y = texture2D(otexture, vec2(opacityUCoords[1].y, opactityTextureHeight)).r;\n opacityG2.z = texture2D(otexture, vec2(opacityUCoords[1].z, opactityTextureHeight)).r;\n opacityG1.xyz *= gradientOpacity;\n opacityG2.xyz *= gradientOpacity;\n\n vec4 opacityG = vec4(opacityG1 - opacityG2, 1.0f);\n // divide by spacing\n opacityG.xyz /= vSpacing;\n opacityG.w = length(opacityG.xyz);\n // rotate to View Coords\n rotateToViewCoord(opacityG.xyz);\n if (!all(equal(opacityG.xyz, vec3(0.0)))) {\n return vec4(normalize(opacityG.xyz),opacityG.w);\n } else {\n return vec4(0.0);\n }\n }\n\n vec4 computeNormalForDensity(vec3 pos, vec3 tstep, out vec3 scalarInterp[2], const int opacityComponent)\n {\n vec3 xvec = vec3(tstep.x, 0.0, 0.0);\n vec3 yvec = vec3(0.0, tstep.y, 0.0);\n vec3 zvec = vec3(0.0, 0.0, tstep.z);\n vec3 texPosPVec[3];\n texPosPVec[0] = pos + xvec;\n texPosPVec[1] = pos + yvec;\n texPosPVec[2] = pos + zvec;\n vec3 texPosNVec[3];\n texPosNVec[0] = pos - xvec;\n texPosNVec[1] = pos - yvec;\n texPosNVec[2] = pos - zvec;\n vec3 g1, g2;\n\n scalarInterp[0].x = getTextureValue(texPosPVec[0])[opacityComponent];\n scalarInterp[0].y = getTextureValue(texPosPVec[1])[opacityComponent];\n scalarInterp[0].z = getTextureValue(texPosPVec[2])[opacityComponent];\n scalarInterp[1].x = getTextureValue(texPosNVec[0])[opacityComponent];\n scalarInterp[1].y = getTextureValue(texPosNVec[1])[opacityComponent];\n scalarInterp[1].z = getTextureValue(texPosNVec[2])[opacityComponent];\n\n #ifdef vtkClippingPlanesOn\n adjustClippedVoxelValues(pos, texPosPVec, scalarInterp[0]);\n adjustClippedVoxelValues(pos, texPosNVec, scalarInterp[1]);\n #endif\n vec4 result;\n result.x = scalarInterp[0].x - scalarInterp[1].x;\n result.y = scalarInterp[0].y - scalarInterp[1].y;\n result.z = scalarInterp[0].z - scalarInterp[1].z;\n // divide by spacing\n result.xyz /= vSpacing;\n result.w = length(result.xyz);\n // rotate to View Coords\n rotateToViewCoord(result.xyz);\n if (length(result.xyz) > 0.0) {\n return vec4(normalize(result.xyz),result.w);\n } else {\n return vec4(0.0);\n }\n }\n #endif\n\n // only works with dependent components\n vec4 computeNormal(vec3 pos, vec3 tstep)\n {\n vec3 xvec = vec3(tstep.x, 0.0, 0.0);\n vec3 yvec = vec3(0.0, tstep.y, 0.0);\n vec3 zvec = vec3(0.0, 0.0, tstep.z);\n vec3 texPosPVec[3];\n texPosPVec[0] = pos + xvec;\n texPosPVec[1] = pos + yvec;\n texPosPVec[2] = pos + zvec;\n vec3 texPosNVec[3];\n texPosNVec[0] = pos - xvec;\n texPosNVec[1] = pos - yvec;\n texPosNVec[2] = pos - zvec;\n vec3 g1, g2;\n g1.x = getTextureValue(texPosPVec[0]).a;\n g1.y = getTextureValue(texPosPVec[1]).a;\n g1.z = getTextureValue(texPosPVec[2]).a;\n g2.x = getTextureValue(texPosNVec[0]).a;\n g2.y = getTextureValue(texPosNVec[1]).a;\n g2.z = getTextureValue(texPosNVec[2]).a;\n #ifdef vtkClippingPlanesOn\n adjustClippedVoxelValues(pos, texPosPVec, g1);\n adjustClippedVoxelValues(pos, texPosNVec, g2);\n #endif\n vec4 result;\n result = vec4(g1 - g2, -1.0);\n // divide by spacing\n result.xyz /= vSpacing;\n result.w = length(result.xyz);\n if (result.w > 0.0){\n // rotate to View Coords\n rotateToViewCoord(result.xyz);\n return vec4(normalize(result.xyz),result.w);\n } else {\n return vec4(0.0);\n }\n }\n#endif\n\n#ifdef vtkImageLabelOutlineOn\nvec3 fragCoordToIndexSpace(vec4 fragCoord) {\n vec4 pcPos = vec4(\n (fragCoord.x / vpWidth - vpOffsetX - 0.5) * 2.0,\n (fragCoord.y / vpHeight - vpOffsetY - 0.5) * 2.0,\n (fragCoord.z - 0.5) * 2.0,\n 1.0);\n\n vec4 worldCoord = PCWCMatrix * pcPos;\n vec4 vertex = (worldCoord/worldCoord.w);\n\n vec3 index = (vWCtoIDX * vertex).xyz;\n\n // half voxel fix for labelmapOutline\n return (index + vec3(0.5)) / vec3(volumeDimensions);\n}\n#endif\n\n//=======================================================================\n// compute the normals and gradient magnitudes for a position\n// for independent components\nmat4 computeMat4Normal(vec3 pos, vec4 tValue, vec3 tstep)\n{\n mat4 result;\n vec4 distX = getTextureValue(pos + vec3(tstep.x, 0.0, 0.0)) - tValue;\n vec4 distY = getTextureValue(pos + vec3(0.0, tstep.y, 0.0)) - tValue;\n vec4 distZ = getTextureValue(pos + vec3(0.0, 0.0, tstep.z)) - tValue;\n\n // divide by spacing\n distX /= vSpacing.x;\n distY /= vSpacing.y;\n distZ /= vSpacing.z;\n\n mat3 rot;\n rot[0] = vPlaneNormal0;\n rot[1] = vPlaneNormal2;\n rot[2] = vPlaneNormal4;\n\n#if !defined(vtkComponent0Proportional)\n result[0].xyz = vec3(distX.r, distY.r, distZ.r);\n result[0].a = length(result[0].xyz);\n result[0].xyz *= rot;\n if (result[0].w > 0.0)\n {\n result[0].xyz /= result[0].w;\n }\n#endif\n\n// optionally compute the 2nd component\n#if vtkNumComponents >= 2 && !defined(vtkComponent1Proportional)\n result[1].xyz = vec3(distX.g, distY.g, distZ.g);\n result[1].a = length(result[1].xyz);\n result[1].xyz *= rot;\n if (result[1].w > 0.0)\n {\n result[1].xyz /= result[1].w;\n }\n#endif\n\n// optionally compute the 3rd component\n#if vtkNumComponents >= 3 && !defined(vtkComponent2Proportional)\n result[2].xyz = vec3(distX.b, distY.b, distZ.b);\n result[2].a = length(result[2].xyz);\n result[2].xyz *= rot;\n if (result[2].w > 0.0)\n {\n result[2].xyz /= result[2].w;\n }\n#endif\n\n// optionally compute the 4th component\n#if vtkNumComponents >= 4 && !defined(vtkComponent3Proportional)\n result[3].xyz = vec3(distX.a, distY.a, distZ.a);\n result[3].a = length(result[3].xyz);\n result[3].xyz *= rot;\n if (result[3].w > 0.0)\n {\n result[3].xyz /= result[3].w;\n }\n#endif\n\n return result;\n}\n\n//=======================================================================\n// global shadow - secondary ray\n#if defined(VolumeShadowOn) || defined(localAmbientOcclusionOn)\nfloat random()\n{\n float rand = fract(sin(dot(gl_FragCoord.xy,vec2(12.9898,78.233)))*43758.5453123);\n float jitter=texture2D(jtexture,gl_FragCoord.xy/32.).r;\n uint pcg_state = floatBitsToUint(jitter);\n uint state = pcg_state;\n pcg_state = pcg_state * uint(747796405) + uint(2891336453);\n uint word = ((state >> ((state >> uint(28)) + uint(4))) ^ state) * uint(277803737);\n return (float((((word >> uint(22)) ^ word) >> 1 ))/float(2147483647) + rand)/2.0;\n}\n#endif\n\n#ifdef VolumeShadowOn\n// henyey greenstein phase function\nfloat phase_function(float cos_angle)\n{\n // divide by 2.0 instead of 4pi to increase intensity\n return ((1.0-anisotropy2)/pow(1.0+anisotropy2-2.0*anisotropy*cos_angle, 1.5))/2.0;\n}\n\n// Computes the intersection between a ray and a box\nstruct Hit\n{\n float tmin;\n float tmax;\n};\n\nstruct Ray\n{\n vec3 origin;\n vec3 dir;\n vec3 invDir;\n};\n\nbool BBoxIntersect(vec3 boundMin, vec3 boundMax, const Ray r, out Hit hit)\n{\n vec3 tbot = r.invDir * (boundMin - r.origin);\n vec3 ttop = r.invDir * (boundMax - r.origin);\n vec3 tmin = min(ttop, tbot);\n vec3 tmax = max(ttop, tbot);\n vec2 t = max(tmin.xx, tmin.yz);\n float t0 = max(t.x, t.y);\n t = min(tmax.xx, tmax.yz);\n float t1 = min(t.x, t.y);\n hit.tmin = t0;\n hit.tmax = t1;\n return t1 > max(t0,0.0);\n}\n\n// As BBoxIntersect requires the inverse of the ray coords,\n// this function is used to avoid numerical issues\nvoid safe_0_vector(inout Ray ray)\n{\n if(abs(ray.dir.x) < EPSILON) ray.dir.x = sign(ray.dir.x) * EPSILON;\n if(abs(ray.dir.y) < EPSILON) ray.dir.y = sign(ray.dir.y) * EPSILON;\n if(abs(ray.dir.z) < EPSILON) ray.dir.z = sign(ray.dir.z) * EPSILON;\n}\n\nfloat volume_shadow(vec3 posIS, vec3 lightDirNormIS)\n{\n float shadow = 1.0;\n float opacity = 0.0;\n\n // modify sample distance with a random number between 1.5 and 3.0\n float sampleDistanceISVS_jitter = sampleDistanceISVS * mix(1.5, 3.0, random());\n float opacityPrev = texture2D(otexture, vec2(getTextureValue(posIS).r * oscale0 + oshift0, 0.5)).r;\n\n // in case the first sample near surface has a very tiled light ray, we need to offset start position\n posIS += sampleDistanceISVS_jitter * lightDirNormIS;\n\n // compute the start and end points for the ray\n Ray ray;\n Hit hit;\n ray.origin = posIS;\n ray.dir = lightDirNormIS;\n safe_0_vector(ray);\n ray.invDir = 1.0/ray.dir;\n\n if(!BBoxIntersect(vec3(0.0),vec3(1.0), ray, hit))\n {\n return 1.0;\n }\n float maxdist = hit.tmax;\n\n // interpolate shadow ray length between: 1 unit of sample distance in IS to SQRT3, based on globalIlluminationReach\n float maxgi = mix(sampleDistanceISVS_jitter,SQRT3,giReach);\n maxdist = min(maxdist,maxgi);\n if(maxdist < EPSILON) {\n return 1.0;\n }\n\n float current_dist = 0.0;\n float current_step = length(sampleDistanceISVS_jitter * lightDirNormIS);\n float clamped_step = 0.0;\n\n vec4 scalar = vec4(0.0);\n while(current_dist < maxdist)\n {\n#ifdef vtkClippingPlanesOn\n vec3 posVC = IStoVC(posIS);\n for (int i = 0; i < clip_numPlanes; ++i)\n {\n if (dot(vec3(vClipPlaneOrigins[i] - posVC), vClipPlaneNormals[i]) > 0.0)\n {\n current_dist = maxdist;\n }\n }\n#endif\n scalar = getTextureValue(posIS);\n opacity = texture2D(otexture, vec2(scalar.r * oscale0 + oshift0, 0.5)).r;\n #if defined(vtkGradientOpacityOn) && !defined(UseIndependentComponents)\n vec4 normal = computeNormal(posIS, vec3(1.0/vec3(volumeDimensions)));\n opacity *= computeGradientOpacityFactor(normal.w, goscale0, goshift0, gomin0, gomax0);\n #endif\n shadow *= 1.0 - opacity;\n\n // optimization: early termination\n if (shadow < EPSILON){\n return 0.0;\n }\n\n clamped_step = min(maxdist - current_dist, current_step);\n posIS += clamped_step * lightDirNormIS;\n current_dist += current_step;\n }\n\n return shadow;\n}\n\nvec3 applyShadowRay(vec3 tColor, vec3 posIS, vec3 viewDirectionVC)\n{\n vec3 vertLight = vec3(0.0);\n vec3 secondary_contrib = vec3(0.0);\n // here we assume only positional light, no effect of cones\n for (int i = 0; i < lightNum; i++)\n {\n #if(vtkLightComplexity==3)\n if (lightPositional[i] == 1){\n vertLight = lightPositionVC[i] - IStoVC(posIS);\n }else{\n vertLight = - lightDirectionVC[i];\n }\n #else\n vertLight = - lightDirectionVC[i];\n #endif\n // here we assume achromatic light, only intensity\n float dDotL = dot(viewDirectionVC, normalize(vertLight));\n // isotropic scatter returns 0.5 instead of 1/4pi to increase intensity\n float phase_attenuation = 0.5;\n if (abs(anisotropy) > EPSILON){\n phase_attenuation = phase_function(dDotL);\n }\n float vol_shadow = volume_shadow(posIS, normalize(rotateToIDX(vertLight)));\n secondary_contrib += tColor * vDiffuse * lightColor[i] * vol_shadow * phase_attenuation;\n secondary_contrib += tColor * vAmbient;\n }\n return secondary_contrib;\n}\n#endif\n\n//=======================================================================\n// local ambient occlusion\n#ifdef localAmbientOcclusionOn\nvec3 sample_direction_uniform(int i)\n{\n float rand = random() * 0.5;\n float theta = PI2 * (kernelSample[i][0] + rand);\n float phi = acos(2.0 * (kernelSample[i][1] + rand) -1.0) / 2.5;\n return normalize(vec3(cos(theta)*sin(phi), sin(theta)*sin(phi), cos(phi)));\n}\n\n// return a matrix that transform startDir into z axis; startDir should be normalized\nmat3 zBaseRotationalMatrix(vec3 startDir){\n vec3 axis = cross(startDir, vec3(0.0,0.0,1.0));\n float cosA = startDir.z;\n float k = 1.0 / (1.0 + cosA);\n mat3 matrix = mat3((axis.x * axis.x * k) + cosA, (axis.y * axis.x * k) - axis.z, (axis.z * axis.x * k) + axis.y,\n (axis.x * axis.y * k) + axis.z, (axis.y * axis.y * k) + cosA, (axis.z * axis.y * k) - axis.x,\n (axis.x * axis.z * k) - axis.y, (axis.y * axis.z * k) + axis.x, (axis.z * axis.z * k) + cosA);\n return matrix;\n}\n\nfloat computeLAO(vec3 posIS, float op, vec3 lightDir, vec4 normal){\n // apply LAO only at selected locations, otherwise return full brightness\n if (normal.w > 0.0 && op > 0.05){\n float total_transmittance = 0.0;\n mat3 inverseRotateBasis = inverse(zBaseRotationalMatrix(normalize(-normal.xyz)));\n vec3 currPos, randomDirStep;\n float weight, transmittance, opacity;\n for (int i = 0; i < kernelSize; i++)\n {\n randomDirStep = inverseRotateBasis * sample_direction_uniform(i) * sampleDistanceIS;\n weight = 1.0 - dot(normalize(lightDir), normalize(randomDirStep));\n currPos = posIS;\n transmittance = 1.0;\n for (int j = 0; j < kernelRadius ; j++){\n currPos += randomDirStep;\n // check if it's at clipping plane, if so return full brightness\n if (all(greaterThan(currPos, vec3(EPSILON))) && all(lessThan(currPos,vec3(1.0-EPSILON)))){\n opacity = texture2D(otexture, vec2(getTextureValue(currPos).r * oscale0 + oshift0, 0.5)).r;\n #ifdef vtkGradientOpacityOn\n opacity *= computeGradientOpacityFactor(normal.w, goscale0, goshift0, gomin0, gomax0);\n #endif\n transmittance *= 1.0 - opacity;\n }\n else{\n break;\n }\n }\n total_transmittance += transmittance / float(kernelRadius) * weight;\n\n // early termination if fully translucent\n if (total_transmittance > 1.0 - EPSILON){\n return 1.0;\n }\n }\n // average transmittance and reduce variance\n return clamp(total_transmittance / float(kernelSize), 0.3, 1.0);\n } else {\n return 1.0;\n }\n}\n#endif\n\n//=======================================================================\n// surface light contribution\n#if vtkLightComplexity > 0\n void applyLighting(inout vec3 tColor, vec4 normal)\n {\n vec3 diffuse = vec3(0.0, 0.0, 0.0);\n vec3 specular = vec3(0.0, 0.0, 0.0);\n float df, sf = 0.0;\n for (int i = 0; i < lightNum; i++){\n df = abs(dot(normal.rgb, -lightDirectionVC[i]));\n diffuse += df * lightColor[i];\n sf = pow( abs(dot(lightHalfAngleVC[i],normal.rgb)), vSpecularPower);\n specular += sf * lightColor[i];\n }\n tColor.rgb = tColor.rgb*(diffuse*vDiffuse + vAmbient) + specular*vSpecular;\n }\n #ifdef SurfaceShadowOn\n #if vtkLightComplexity < 3\n vec3 applyLightingDirectional(vec3 posIS, vec4 tColor, vec4 normal)\n {\n // everything in VC\n vec3 diffuse = vec3(0.0);\n vec3 specular = vec3(0.0);\n #ifdef localAmbientOcclusionOn\n vec3 ambient = vec3(0.0);\n #endif\n vec3 vertLightDirection;\n for (int i = 0; i < lightNum; i++){\n float ndotL,vdotR;\n vertLightDirection = lightDirectionVC[i];\n ndotL = dot(normal.xyz, vertLightDirection);\n if (ndotL < 0.0 && twoSidedLighting)\n {\n ndotL = -ndotL;\n }\n if (ndotL > 0.0)\n {\n diffuse += ndotL * lightColor[i];\n //specular\n vdotR = dot(-rayDirVC, normalize(2.0 * ndotL * -normal.xyz + vertLightDirection));\n if (vdotR > 0.0)\n {\n specular += pow(vdotR, vSpecularPower) * lightColor[i];\n }\n }\n #ifdef localAmbientOcclusionOn\n ambient += computeLAO(posIS, tColor.a, vertLightDirection, normal);\n #endif\n }\n #ifdef localAmbientOcclusionOn\n return tColor.rgb * (diffuse * vDiffuse + vAmbient * ambient) + specular*vSpecular;\n #else\n return tColor.rgb * (diffuse * vDiffuse + vAmbient) + specular*vSpecular;\n #endif\n }\n #else\n vec3 applyLightingPositional(vec3 posIS, vec4 tColor, vec4 normal, vec3 posVC)\n {\n // everything in VC\n vec3 diffuse = vec3(0.0);\n vec3 specular = vec3(0.0);\n #ifdef localAmbientOcclusionOn\n vec3 ambient = vec3(0.0);\n #endif\n vec3 vertLightDirection;\n for (int i = 0; i < lightNum; i++){\n float distance,attenuation,ndotL,vdotR;\n vec3 lightDir;\n if (lightPositional[i] == 1){\n lightDir = lightDirectionVC[i];\n vertLightDirection = posVC - lightPositionVC[i];\n distance = length(vertLightDirection);\n vertLightDirection = normalize(vertLightDirection);\n attenuation = 1.0 / (lightAttenuation[i].x\n + lightAttenuation[i].y * distance\n + lightAttenuation[i].z * distance * distance);\n // per OpenGL standard cone angle is 90 or less for a spot light\n if (lightConeAngle[i] <= 90.0){\n float coneDot = dot(vertLightDirection, lightDir);\n if (coneDot >= cos(radians(lightConeAngle[i]))){ // if inside cone\n attenuation = attenuation * pow(coneDot, lightExponent[i]);\n }\n else {\n attenuation = 0.0;\n }\n }\n ndotL = dot(normal.xyz, vertLightDirection);\n if (ndotL < 0.0 && twoSidedLighting)\n {\n ndotL = -ndotL;\n }\n if (ndotL > 0.0)\n {\n diffuse += ndotL * attenuation * lightColor[i];\n //specular\n vdotR = dot(-rayDirVC, normalize(2.0 * ndotL * -normal.xyz + vertLightDirection));\n if (vdotR > 0.0)\n {\n specular += pow(vdotR, vSpecularPower) * attenuation * lightColor[i];\n }\n }\n #ifdef localAmbientOcclusionOn\n ambient += computeLAO(posIS, tColor.a, vertLightDirection, normal);\n #endif\n } else {\n vertLightDirection = lightDirectionVC[i];\n ndotL = dot(normal.xyz, vertLightDirection);\n if (ndotL < 0.0 && twoSidedLighting)\n {\n ndotL = -ndotL;\n }\n if (ndotL > 0.0)\n {\n diffuse += ndotL * lightColor[i];\n //specular\n vdotR = dot(-rayDirVC, normalize(2.0 * ndotL * -normal.xyz + vertLightDirection));\n if (vdotR > 0.0)\n {\n specular += pow(vdotR, vSpecularPower) * lightColor[i];\n }\n }\n #ifdef localAmbientOcclusionOn\n ambient += computeLAO(posIS, tColor.a, vertLightDirection, normal);\n #endif\n }\n }\n #ifdef localAmbientOcclusionOn\n return tColor.rgb * (diffuse * vDiffuse + vAmbient * ambient) + specular*vSpecular;\n #else\n return tColor.rgb * (diffuse * vDiffuse + vAmbient) + specular*vSpecular;\n #endif\n }\n #endif\n #endif\n#endif\n\n// LAO of surface shadows and volume shadows only work with dependent components\nvec3 applyAllLightning(vec3 tColor, float alpha, vec3 posIS, vec4 normalLight) {\n #if vtkLightComplexity > 0\n // surface shadows if needed\n #ifdef SurfaceShadowOn\n #if vtkLightComplexity < 3\n vec3 tColorS = applyLightingDirectional(posIS, vec4(tColor, alpha), normalLight);\n #else\n vec3 tColorS = applyLightingPositional(posIS, vec4(tColor, alpha), normalLight, IStoVC(posIS));\n #endif\n #endif\n\n // volume shadows if needed\n #ifdef VolumeShadowOn\n vec3 tColorVS = applyShadowRay(tColor, posIS, rayDirVC);\n #endif\n\n // merge\n #ifdef VolumeShadowOn\n #ifdef SurfaceShadowOn\n // surface shadows + volumetric shadows\n float vol_coef = volumetricScatteringBlending * (1.0 - alpha / 2.0) * (1.0 - atan(normalLight.w) * INV4PI);\n tColor = (1.0-vol_coef) * tColorS + vol_coef * tColorVS;\n #else\n // volumetric shadows only\n tColor = tColorVS;\n #endif\n #else\n #ifdef SurfaceShadowOn\n // surface shadows only\n tColor = tColorS;\n #else\n // no shadows\n applyLighting(tColor, normal3);\n #endif\n #endif\n #endif\n return tColor;\n}\n\n//=======================================================================\n// Given a texture value compute the color and opacity\n//\nvec4 getColorForValue(vec4 tValue, vec3 posIS, vec3 tstep)\n{\n#ifdef vtkImageLabelOutlineOn\n vec3 centerPosIS = fragCoordToIndexSpace(gl_FragCoord); // pos in texture space\n vec4 centerValue = getTextureValue(centerPosIS);\n bool pixelOnBorder = false;\n vec4 tColor = texture2D(ctexture, vec2(centerValue.r * cscale0 + cshift0, 0.5));\n\n // Get alpha of segment from opacity function.\n tColor.a = texture2D(otexture, vec2(centerValue.r * oscale0 + oshift0, 0.5)).r;\n\n int segmentIndex = int(centerValue.r * 255.0);\n \n // Use texture sampling for outlineThickness\n float textureCoordinate = float(segmentIndex - 1) / 1024.0;\n float textureValue = texture2D(ttexture, vec2(textureCoordinate, 0.5)).r;\n\n int actualThickness = int(textureValue * 255.0);\n\n if (actualThickness == 0) {\n return vec4(0, 0, 1, 1);\n }\n\n // If it is the background (segment index 0), we should quickly bail out. \n // Previously, this was determined by tColor.a, which was incorrect as it\n // prevented the outline from appearing when the fill is 0.\n if (segmentIndex == 0){\n return vec4(0, 0, 0, 0);\n }\n\n // Only perform outline check on fragments rendering voxels that aren't invisible.\n // Saves a bunch of needless checks on the background.\n // TODO define epsilon when building shader?\n for (int i = -actualThickness; i <= actualThickness; i++) {\n for (int j = -actualThickness; j <= actualThickness; j++) {\n if (i == 0 || j == 0) {\n continue;\n }\n\n vec4 neighborPixelCoord = vec4(gl_FragCoord.x + float(i),\n gl_FragCoord.y + float(j),\n gl_FragCoord.z, gl_FragCoord.w);\n\n vec3 neighborPosIS = fragCoordToIndexSpace(neighborPixelCoord);\n vec4 value = getTextureValue(neighborPosIS);\n\n // If any of my neighbours are not the same value as I\n // am, this means I am on the border of the segment.\n // We can break the loops\n if (any(notEqual(value, centerValue))) {\n pixelOnBorder = true;\n break;\n }\n }\n\n if (pixelOnBorder == true) {\n break;\n }\n }\n\n // If I am on the border, I am displayed at full opacity\n if (pixelOnBorder == true) {\n tColor.a = outlineOpacity;\n }\n\n return tColor;\n\n#else\n // compute the normal and gradient magnitude if needed\n // We compute it as a vec4 if possible otherwise a mat4\n\n #ifdef UseIndependentComponents\n // sample textures\n vec3 tColor0 = texture2D(ctexture, vec2(tValue.r * cscale0 + cshift0, height0)).rgb;\n float pwfValue0 = texture2D(otexture, vec2(tValue.r * oscale0 + oshift0, height0)).r;\n\n #if vtkNumComponents > 1\n vec3 tColor1 = texture2D(ctexture, vec2(tValue.g * cscale1 + cshift1, height1)).rgb;\n float pwfValue1 = texture2D(otexture, vec2(tValue.g * oscale1 + oshift1, height1)).r;\n\n #if vtkNumComponents > 2\n vec3 tColor2 = texture2D(ctexture, vec2(tValue.b * cscale2 + cshift2, height2)).rgb;\n float pwfValue2 = texture2D(otexture, vec2(tValue.b * oscale2 + oshift2, height2)).r;\n\n #if vtkNumComponents > 3\n vec3 tColor3 = texture2D(ctexture, vec2(tValue.a * cscale3 + cshift3, height3)).rgb;\n float pwfValue3 = texture2D(otexture, vec2(tValue.a * oscale3 + oshift3, height3)).r;\n #endif\n #endif\n #endif\n\n #if !defined(vtkCustomComponentsColorMix)\n // default path for component color mix\n\n // compute the normal vectors as needed\n #if (vtkLightComplexity > 0) || defined(vtkGradientOpacityOn)\n mat4 normalMat = computeMat4Normal(posIS, tValue, tstep);\n #endif\n\n // compute gradient opacity factors as needed\n vec4 goFactor = vec4(1.0, 1.0 ,1.0 ,1.0);\n #if defined(vtkGradientOpacityOn)\n #if !defined(vtkComponent0Proportional)\n goFactor.x =\n computeGradientOpacityFactor(normalMat[0].a, goscale0, goshift0, gomin0, gomax0);\n #endif\n #if vtkNumComponents > 1\n #if !defined(vtkComponent1Proportional)\n goFactor.y =\n computeGradientOpacityFactor(normalMat[1].a, goscale1, goshift1, gomin1, gomax1);\n #endif\n #if vtkNumComponents > 2\n #if !defined(vtkComponent2Proportional)\n goFactor.z =\n computeGradientOpacityFactor(normalMat[2].a, goscale2, goshift2, gomin2, gomax2);\n #endif\n #if vtkNumComponents > 3\n #if !defined(vtkComponent3Proportional)\n goFactor.w =\n computeGradientOpacityFactor(normalMat[3].a, goscale3, goshift3, gomin3, gomax3);\n #endif\n #endif\n #endif\n #endif\n #endif\n\n // process color and opacity for each component\n #if !defined(vtkComponent0Proportional)\n float alpha = goFactor.x*mix0*pwfValue0;\n #if vtkLightComplexity > 0\n applyLighting(tColor0, normalMat[0]);\n #endif\n #else\n tColor0 *= pwfValue0;\n float alpha = mix(pwfValue0, 1.0, (1.0 - mix0));\n #endif\n\n #if vtkNumComponents > 1\n #if !defined(vtkComponent1Proportional)\n alpha += goFactor.y*mix1*pwfValue1;\n #if vtkLightComplexity > 0\n applyLighting(tColor1, normalMat[1]);\n #endif\n #else\n tColor1 *= pwfValue1;\n alpha *= mix(pwfValue1, 1.0, (1.0 - mix1));\n #endif\n\n #if vtkNumComponents > 2\n #if !defined(vtkComponent2Proportional)\n alpha += goFactor.z*mix2*pwfValue2;\n #if vtkLightComplexity > 0\n applyLighting(tColor2, normalMat[2]);\n #endif\n #else\n tColor2 *= pwfValue2;\n alpha *= mix(pwfValue2, 1.0, (1.0 - mix2));\n #endif\n #endif\n\n #if vtkNumComponents > 3\n #if !defined(vtkComponent3Proportional)\n alpha += goFactor.w*mix3*pwfValue3;\n #if vtkLightComplexity > 0\n applyLighting(tColor3, normalMat[3]);\n #endif\n #else\n tColor3 *= pwfValue3;\n alpha *= mix(pwfValue3, 1.0, (1.0 - mix3));\n #endif\n #endif\n #endif\n\n // perform final independent blend\n vec3 tColor = mix0 * tColor0;\n #if vtkNumComponents > 1\n tColor += mix1 * tColor1;\n #if vtkNumComponents > 2\n tColor += mix2 * tColor2;\n #if vtkNumComponents > 3\n tColor += mix3 * tColor3;\n #endif\n #endif\n #endif\n\n return vec4(tColor, alpha);\n #else\n /*\n * Mix the color information from all the independent components to get a single rgba output\n * Gradient opactity factors and normals are not computed\n *\n * You can compute these using:\n * - computeMat4Normal: always available, compute normal only for non proportional components, used by default independent component mix\n * - computeDensityNormal & computeNormalForDensity: available if ((LightComplexity > 0) || GradientOpacityOn) && ComputeNormalFromOpacity),\n * used by dependent component color mix, see code for Additive preset in OpenGl/VolumeMapper\n * - computeGradientOpacityFactor: always available, used in a lot of places\n *\n * Using applyAllLightning() is advised for shading but some features don't work well with it (volume shadows, LAO)\n * mix0, mix1, ... are defined for each component that is used and correspond to the componentWeight\n */\n //VTK::CustomComponentsColorMix::Impl\n #endif\n #else\n // dependent components\n\n // compute normal if needed\n #if (vtkLightComplexity > 0) || defined(vtkGradientOpacityOn)\n // use component 3 of the opacity texture as getTextureValue() sets alpha to the opacity value\n #ifdef vtkComputeNormalFromOpacity\n vec3 scalarInterp[2];\n vec4 normal0 = computeNormalForDensity(posIS, tstep, scalarInterp, 3);\n #else\n vec4 normal0 = computeNormal(posIS, tstep);\n #endif\n #endif\n\n // compute gradient opacity factor enabled\n #if defined(vtkGradientOpacityOn)\n float gradientOpacity = computeGradientOpacityFactor(normal0.a, goscale0, goshift0, gomin0, gomax0);\n #else\n const float gradientOpacity = 1.0;\n #endif\n\n // get color and opacity\n #if vtkNumComponents == 1\n vec3 tColor = texture2D(ctexture, vec2(tValue.r * cscale0 + cshift0, 0.5)).rgb;\n float alpha = gradientOpacity*texture2D(otexture, vec2(tValue.r * oscale0 + oshift0, 0.5)).r;\n if (alpha < EPSILON){\n return vec4(0.0);\n }\n #endif\n #if vtkNumComponents == 2\n vec3 tColor = vec3(tValue.r * cscale0 + cshift0);\n float alpha = gradientOpacity*texture2D(otexture, vec2(tValue.a * oscale1 + oshift1, 0.5)).r;\n #endif\n #if vtkNumComponents == 3\n vec3 tColor;\n tColor.r = tValue.r * cscale0 + cshift0;\n tColor.g = tValue.g * cscale1 + cshift1;\n tColor.b = tValue.b * cscale2 + cshift2;\n float alpha = gradientOpacity*texture2D(otexture, vec2(tValue.a * oscale0 + oshift0, 0.5)).r;\n #endif\n #if vtkNumComponents == 4\n vec3 tColor;\n tColor.r = tValue.r * cscale0 + cshift0;\n tColor.g = tValue.g * cscale1 + cshift1;\n tColor.b = tValue.b * cscale2 + cshift2;\n float alpha = gradientOpacity*texture2D(otexture, vec2(tValue.a * oscale3 + oshift3, 0.5)).r;\n #endif\n\n // lighting\n #if (vtkLightComplexity > 0)\n #ifdef vtkComputeNormalFromOpacity\n vec4 normalLight;\n if (!all(equal(normal0, vec4(0.0)))) {\n scalarInterp[0] = scalarInterp[0] * oscale0 + oshift0;\n scalarInterp[1] = scalarInterp[1] * oscale0 + oshift0;\n normalLight = computeDensityNormal(scalarInterp, 0.5, gradientOpacity);\n if (all(equal(normalLight, vec4(0.0)))) {\n normalLight = normal0;\n }\n }\n #else\n vec4 normalLight = normal0;\n #endif\n tColor = applyAllLightning(tColor, alpha, posIS, normalLight);\n #endif\n\n return vec4(tColor, alpha);\n #endif // dependent\n#endif\n}\n\nbool valueWithinScalarRange(vec4 val, vec4 min, vec4 max) {\n bool withinRange = false;\n #if vtkNumComponents == 1\n if (val.r >= min.r && val.r <= max.r) {\n withinRange = true;\n }\n #else\n #ifdef UseIndependentComponents\n #if vtkNumComponents == 2\n if (val.r >= min.r && val.r <= max.r &&\n val.g >= min.g && val.g <= max.g) {\n withinRange = true;\n }\n #else\n if (all(greaterThanEqual(val, ipScalarRangeMin)) &&\n all(lessThanEqual(val, ipScalarRangeMax))) {\n withinRange = true;\n }\n #endif\n #endif\n #endif\n return withinRange;\n}\n\n//=======================================================================\n// Apply the specified blend mode operation along the ray's path.\n//\nvoid applyBlend(vec3 posIS, vec3 endIS, vec3 tdims)\n{\n vec3 tstep = 1.0/tdims;\n\n // start slightly inside and apply some jitter\n vec3 delta = endIS - posIS;\n vec3 stepIS = normalize(delta)*sampleDistanceIS;\n float raySteps = length(delta)/sampleDistanceIS;\n\n // avoid 0.0 jitter\n float jitter = 0.01 + 0.99*texture2D(jtexture, gl_FragCoord.xy/32.0).r;\n float stepsTraveled = jitter;\n\n // local vars for the loop\n vec4 color = vec4(0.0, 0.0, 0.0, 0.0);\n vec4 tValue;\n vec4 tColor;\n\n // if we have less than one step then pick the middle point\n // as our value\n // if (raySteps <= 1.0)\n // {\n // posIS = (posIS + endIS)*0.5;\n // }\n\n // Perform initial step at the volume boundary\n // compute the scalar\n tValue = getTextureValue(posIS);\n\n #if vtkBlendMode == 0 // COMPOSITE_BLEND\n // now map through opacity and color\n tColor = getColorForValue(tValue, posIS, tstep);\n\n // handle very thin volumes\n if (raySteps <= 1.0)\n {\n tColor.a = 1.0 - pow(1.0 - tColor.a, raySteps);\n gl_FragData[0] = tColor;\n return;\n }\n\n tColor.a = 1.0 - pow(1.0 - tColor.a, jitter);\n color = vec4(tColor.rgb*tColor.a, tColor.a);\n posIS += (jitter*stepIS);\n\n for (int i = 0; i < //VTK::MaximumSamplesValue ; ++i)\n {\n if (stepsTraveled + 1.0 >= raySteps) { break; }\n\n // compute the scalar\n tValue = getTextureValue(posIS);\n\n // now map through opacity and color\n tColor = getColorForValue(tValue, posIS, tstep);\n\n float mix = (1.0 - color.a);\n\n // this line should not be needed but nvidia seems to not handle\n // the break correctly on windows/chrome 58 angle\n //mix = mix * sign(max(raySteps - stepsTraveled - 1.0, 0.0));\n\n color = color + vec4(tColor.rgb*tColor.a, tColor.a)*mix;\n stepsTraveled++;\n posIS += stepIS;\n if (color.a > 0.99) { color.a = 1.0; break; }\n }\n\n if (color.a < 0.99 && (raySteps - stepsTraveled) > 0.0)\n {\n posIS = endIS;\n\n // compute the scalar\n tValue = getTextureValue(posIS);\n\n // now map through opacity and color\n tColor = getColorForValue(tValue, posIS, tstep);\n tColor.a = 1.0 - pow(1.0 - tColor.a, raySteps - stepsTraveled);\n\n float mix = (1.0 - color.a);\n color = color + vec4(tColor.rgb*tColor.a, tColor.a)*mix;\n }\n\n gl_FragData[0] = vec4(color.rgb/color.a, color.a);\n #endif\n #if vtkBlendMode == 1 || vtkBlendMode == 2\n // MAXIMUM_INTENSITY_BLEND || MINIMUM_INTENSITY_BLEND\n // Find maximum/minimum intensity along the ray.\n\n // Define the operation we will use (min or max)\n #if vtkBlendMode == 1\n #define OP max\n #else\n #define OP min\n #endif\n\n // If the clipping range is shorter than the sample distance\n // we can skip the sampling loop along the ray.\n if (raySteps <= 1.0)\n {\n gl_FragData[0] = getColorForValue(tValue, posIS, tstep);\n return;\n }\n\n vec4 value = tValue;\n posIS += (jitter*stepIS);\n\n // Sample along the ray until MaximumSamplesValue,\n // ending slightly inside the total distance\n for (int i = 0; i < //VTK::MaximumSamplesValue ; ++i)\n {\n // If we have reached the last step, break\n if (stepsTraveled + 1.0 >= raySteps) { break; }\n\n // compute the scalar\n tValue = getTextureValue(posIS);\n\n // Update the maximum value if necessary\n value = OP(tValue, value);\n\n // Otherwise, continue along the ray\n stepsTraveled++;\n posIS += stepIS;\n }\n\n // Perform the last step along the ray using the\n // residual distance\n posIS = endIS;\n tValue = getTextureValue(posIS);\n value = OP(tValue, value);\n\n // Now map through opacity and color\n gl_FragData[0] = getColorForValue(value, posIS, tstep);\n #endif\n #if vtkBlendMode == 3 || vtkBlendMode == 4 //AVERAGE_INTENSITY_BLEND || ADDITIVE_BLEND\n vec4 sum = vec4(0.);\n\n if (valueWithinScalarRange(tValue, ipScalarRangeMin, ipScalarRangeMax)) {\n sum += tValue;\n }\n\n if (raySteps <= 1.0) {\n gl_FragData[0] = getColorForValue(sum, posIS, tstep);\n return;\n }\n\n posIS += (jitter*stepIS);\n\n // Sample along the ray until MaximumSamplesValue,\n // ending slightly inside the total distance\n for (int i = 0; i < //VTK::MaximumSamplesValue ; ++i)\n {\n // If we have reached the last step, break\n if (stepsTraveled + 1.0 >= raySteps) { break; }\n\n // compute the scalar\n tValue = getTextureValue(posIS);\n\n // One can control the scalar range by setting the AverageIPScalarRange to disregard scalar values, not in the range of interest, from the average computation.\n // Notes:\n // - We are comparing all values in the texture to see if any of them\n // are outside of the scalar range. In the future we might want to allow\n // scalar ranges for each component.\n if (valueWithinScalarRange(tValue, ipScalarRangeMin, ipScalarRangeMax)) {\n // Sum the values across each step in the path\n sum += tValue;\n }\n stepsTraveled++;\n posIS += stepIS;\n }\n\n // Perform the last step along the ray using the\n // residual distance\n posIS = endIS;\n\n // compute the scalar\n tValue = getTextureValue(posIS);\n\n // One can control the scalar range by setting the IPScalarRange to disregard scalar values, not in the range of interest, from the average computation\n if (valueWithinScalarRange(tValue, ipScalarRangeMin, ipScalarRangeMax)) {\n sum += tValue;\n\n stepsTraveled++;\n }\n\n #if vtkBlendMode == 3 // Average\n sum /= vec4(stepsTraveled, stepsTraveled, stepsTraveled, 1.0);\n #endif\n\n gl_FragData[0] = getColorForValue(sum, posIS, tstep);\n #endif\n #if vtkBlendMode == 5 // RADON\n float normalizedRayIntensity = 1.0;\n\n // handle very thin volumes\n if (raySteps <= 1.0)\n {\n tValue = getTextureValue(posIS);\n normalizedRayIntensity = normalizedRayIntensity - sampleDistance*texture2D(otexture, vec2(tValue.r * oscale0 + oshift0, 0.5)).r;\n gl_FragData[0] = texture2D(ctexture, vec2(normalizedRayIntensity, 0.5));\n return;\n }\n\n posIS += (jitter*stepIS);\n\n for (int i = 0; i < //VTK::MaximumSamplesValue ; ++i)\n {\n if (stepsTraveled + 1.0 >= raySteps) { break; }\n\n // compute the scalar value\n tValue = getTextureValue(posIS);\n\n // Convert scalar value to normalizedRayIntensity coefficient and accumulate normalizedRayIntensity\n normalizedRayIntensity = normalizedRayIntensity - sampleDistance*texture2D(otexture, vec2(tValue.r * oscale0 + oshift0, 0.5)).r;\n\n posIS += stepIS;\n stepsTraveled++;\n }\n\n // map normalizedRayIntensity to color\n gl_FragData[0] = texture2D(ctexture, vec2(normalizedRayIntensity , 0.5));\n\n #endif\n}\n\n//=======================================================================\n// Compute a new start and end point for a given ray based\n// on the provided bounded clipping plane (aka a rectangle)\nvoid getRayPointIntersectionBounds(\n vec3 rayPos, vec3 rayDir,\n vec3 planeDir, float planeDist,\n inout vec2 tbounds, vec3 vPlaneX, vec3 vPlaneY,\n float vSize1, float vSize2)\n{\n float result = dot(rayDir, planeDir);\n if (abs(result) < 1e-6)\n {\n return;\n }\n result = -1.0 * (dot(rayPos, planeDir) + planeDist) / result;\n vec3 xposVC = rayPos + rayDir*result;\n vec3 vxpos = xposVC - vOriginVC;\n vec2 vpos = vec2(\n dot(vxpos, vPlaneX),\n dot(vxpos, vPlaneY));\n\n // on some apple nvidia systems this does not work\n // if (vpos.x < 0.0 || vpos.x > vSize1 ||\n // vpos.y < 0.0 || vpos.y > vSize2)\n // even just\n // if (vpos.x < 0.0 || vpos.y < 0.0)\n // fails\n // so instead we compute a value that represents in and out\n //and then compute the return using this value\n float xcheck = max(0.0, vpos.x * (vpos.x - vSize1)); // 0 means in bounds\n float check = sign(max(xcheck, vpos.y * (vpos.y - vSize2))); // 0 means in bounds, 1 = out\n\n tbounds = mix(\n vec2(min(tbounds.x, result), max(tbounds.y, result)), // in value\n tbounds, // out value\n check); // 0 in 1 out\n}\n\n//=======================================================================\n// given a\n// - ray direction (rayDir)\n// - starting point (vertexVCVSOutput)\n// - bounding planes of the volume\n// - optionally depth buffer values\n// - far clipping plane\n// compute the start/end distances of the ray we need to cast\nvec2 computeRayDistances(vec3 rayDir, vec3 tdims)\n{\n vec2 dists = vec2(100.0*camFar, -1.0);\n\n vec3 vSize = vSpacing*tdims;\n\n // all this is in View Coordinates\n getRayPointIntersectionBounds(vertexVCVSOutput, rayDir,\n vPlaneNormal0, vPlaneDistance0, dists, vPlaneNormal2, vPlaneNormal4,\n vSize.y, vSize.z);\n getRayPointIntersectionBounds(vertexVCVSOutput, rayDir,\n vPlaneNormal1, vPlaneDistance1, dists, vPlaneNormal2, vPlaneNormal4,\n vSize.y, vSize.z);\n getRayPointIntersectionBounds(vertexVCVSOutput, rayDir,\n vPlaneNormal2, vPlaneDistance2, dists, vPlaneNormal0, vPlaneNormal4,\n vSize.x, vSize.z);\n getRayPointIntersectionBounds(vertexVCVSOutput, rayDir,\n vPlaneNormal3, vPlaneDistance3, dists, vPlaneNormal0, vPlaneNormal4,\n vSize.x, vSize.z);\n getRayPointIntersectionBounds(vertexVCVSOutput, rayDir,\n vPlaneNormal4, vPlaneDistance4, dists, vPlaneNormal0, vPlaneNormal2,\n vSize.x, vSize.y);\n getRayPointIntersectionBounds(vertexVCVSOutput, rayDir,\n vPlaneNormal5, vPlaneDistance5, dists, vPlaneNormal0, vPlaneNormal2,\n vSize.x, vSize.y);\n\n //VTK::ClipPlane::Impl\n\n // do not go behind front clipping plane\n dists.x = max(0.0,dists.x);\n\n // do not go PAST far clipping plane\n float farDist = -camThick/rayDir.z;\n dists.y = min(farDist,dists.y);\n\n // Do not go past the zbuffer value if set\n // This is used for intermixing opaque geometry\n //VTK::ZBuffer::Impl\n\n return dists;\n}\n\n//=======================================================================\n// Compute the index space starting position (pos) and end\n// position\n//\nvoid computeIndexSpaceValues(out vec3 pos, out vec3 endPos, vec3 rayDir, vec2 dists)\n{\n // compute starting and ending values in volume space\n pos = vertexVCVSOutput + dists.x*rayDir;\n pos = pos - vOriginVC;\n // convert to volume basis and origin\n pos = vec3(\n dot(pos, vPlaneNormal0),\n dot(pos, vPlaneNormal2),\n dot(pos, vPlaneNormal4));\n\n endPos = vertexVCVSOutput + dists.y*rayDir;\n endPos = endPos - vOriginVC;\n endPos = vec3(\n dot(endPos, vPlaneNormal0),\n dot(endPos, vPlaneNormal2),\n dot(endPos, vPlaneNormal4));\n\n float delta = length(endPos - pos);\n\n pos *= vVCToIJK;\n endPos *= vVCToIJK;\n\n float delta2 = length(endPos - pos);\n sampleDistanceIS = sampleDistance*delta2/delta;\n #ifdef VolumeShadowOn\n sampleDistanceISVS = sampleDistanceIS * volumeShadowSamplingDistFactor;\n #endif\n}\n\nvoid main()\n{\n\n if (cameraParallel == 1)\n {\n // Camera is parallel, so the rayDir is just the direction of the camera.\n rayDirVC = vec3(0.0, 0.0, -1.0);\n } else {\n // camera is at 0,0,0 so rayDir for perspective is just the vc coord\n rayDirVC = normalize(vertexVCVSOutput);\n }\n\n vec3 tdims = vec3(volumeDimensions);\n\n // compute the start and end points for the ray\n vec2 rayStartEndDistancesVC = computeRayDistances(rayDirVC, tdims);\n\n // do we need to composite? aka does the ray have any length\n // If not, bail out early\n if (rayStartEndDistancesVC.y <= rayStartEndDistancesVC.x)\n {\n discard;\n }\n\n // IS = Index Space\n vec3 posIS;\n vec3 endIS;\n computeIndexSpaceValues(posIS, endIS, rayDirVC, rayStartEndDistancesVC);\n\n // Perform the blending operation along the ray\n applyBlend(posIS, endIS, tdims);\n}\n";
|
|
14939
|
+
var vtkVolumeFS = "//VTK::System::Dec\n\n/*=========================================================================\n\n Program: Visualization Toolkit\n Module: vtkVolumeFS.glsl\n\n Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen\n All rights reserved.\n See Copyright.txt or http://www.kitware.com/Copyright.htm for details.\n\n This software is distributed WITHOUT ANY WARRANTY; without even\n the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR\n PURPOSE. See the above copyright notice for more information.\n\n=========================================================================*/\n// Template for the volume mappers fragment shader\n\n// the output of this shader\n//VTK::Output::Dec\n\nvarying vec3 vertexVCVSOutput;\n\n// first declare the settings from the mapper\n// that impact the code paths in here\n\n// always set vtkNumComponents 1,2,3,4\n//VTK::NumComponents\n\n// possibly define vtkTrilinearOn\n//VTK::TrilinearOn\n\n// possibly define UseIndependentComponents\n//VTK::IndependentComponentsOn\n\n// possibly define vtkCustomComponentsColorMix\n//VTK::CustomComponentsColorMixOn\n\n// possibly define any \"proportional\" components\n//VTK::vtkProportionalComponents\n\n// possibly define any components that are forced to nearest interpolation\n//VTK::vtkForceNearestComponents\n\n// Define the blend mode to use\n#define vtkBlendMode //VTK::BlendMode\n\n// Possibly define vtkImageLabelOutlineOn\n//VTK::ImageLabelOutlineOn\n\n#ifdef vtkImageLabelOutlineOn\n\nuniform float outlineOpacity;\nuniform float vpWidth;\nuniform float vpHeight;\nuniform float vpOffsetX;\nuniform float vpOffsetY;\nuniform mat4 PCWCMatrix;\nuniform mat4 vWCtoIDX;\n#endif\n\n// define vtkLightComplexity\n//VTK::LightComplexity\n#if vtkLightComplexity > 0\nuniform float vSpecularPower;\nuniform float vAmbient;\nuniform float vDiffuse;\nuniform float vSpecular;\n//VTK::Light::Dec\n#endif\n\n//VTK::VolumeShadowOn\n//VTK::SurfaceShadowOn\n//VTK::localAmbientOcclusionOn\n//VTK::LAO::Dec\n//VTK::VolumeShadow::Dec\n\n// define vtkComputeNormalFromOpacity\n//VTK::vtkComputeNormalFromOpacity\n\n// possibly define vtkGradientOpacityOn\n//VTK::GradientOpacityOn\n#ifdef vtkGradientOpacityOn\nuniform float goscale0;\nuniform float goshift0;\nuniform float gomin0;\nuniform float gomax0;\n#ifdef UseIndependentComponents\n#if vtkNumComponents > 1\nuniform float goscale1;\nuniform float goshift1;\nuniform float gomin1;\nuniform float gomax1;\n#if vtkNumComponents > 2\nuniform float goscale2;\nuniform float goshift2;\nuniform float gomin2;\nuniform float gomax2;\n#if vtkNumComponents > 3\nuniform float goscale3;\nuniform float goshift3;\nuniform float gomin3;\nuniform float gomax3;\n#endif\n#endif\n#endif\n#endif\n#endif\n\n// if you want to see the raw tiled\n// data in webgl1 uncomment the following line\n// #define debugtile\n\n// camera values\nuniform float camThick;\nuniform float camNear;\nuniform float camFar;\nuniform int cameraParallel;\n\n// values describing the volume geometry\nuniform vec3 vOriginVC;\nuniform vec3 vSpacing;\nuniform ivec3 volumeDimensions; // 3d texture dimensions\nuniform vec3 vPlaneNormal0;\nuniform float vPlaneDistance0;\nuniform vec3 vPlaneNormal1;\nuniform float vPlaneDistance1;\nuniform vec3 vPlaneNormal2;\nuniform float vPlaneDistance2;\nuniform vec3 vPlaneNormal3;\nuniform float vPlaneDistance3;\nuniform vec3 vPlaneNormal4;\nuniform float vPlaneDistance4;\nuniform vec3 vPlaneNormal5;\nuniform float vPlaneDistance5;\n\n//VTK::ClipPlane::Dec\n\n// opacity and color textures\nuniform sampler2D otexture;\nuniform float oshift0;\nuniform float oscale0;\nuniform sampler2D ctexture;\nuniform float cshift0;\nuniform float cscale0;\n\n#if vtkNumComponents >= 2\nuniform float oshift1;\nuniform float oscale1;\nuniform float cshift1;\nuniform float cscale1;\n#endif\n#if vtkNumComponents >= 3\nuniform float oshift2;\nuniform float oscale2;\nuniform float cshift2;\nuniform float cscale2;\n#endif\n#if vtkNumComponents >= 4\nuniform float oshift3;\nuniform float oscale3;\nuniform float cshift3;\nuniform float cscale3;\n#endif\n\n// jitter texture\nuniform sampler2D jtexture;\nuniform sampler2D ttexture;\n\n\n// some 3D texture values\nuniform float sampleDistance;\nuniform vec3 vVCToIJK;\n\n// the heights defined below are the locations\n// for the up to four components of the tfuns\n// the tfuns have a height of 2XnumComps pixels so the\n// values are computed to hit the middle of the two rows\n// for that component\n#ifdef UseIndependentComponents\n#if vtkNumComponents == 1\nuniform float mix0;\n#define height0 0.5\n#endif\n#if vtkNumComponents == 2\nuniform float mix0;\nuniform float mix1;\n#define height0 0.25\n#define height1 0.75\n#endif\n#if vtkNumComponents == 3\nuniform float mix0;\nuniform float mix1;\nuniform float mix2;\n#define height0 0.17\n#define height1 0.5\n#define height2 0.83\n#endif\n#if vtkNumComponents == 4\nuniform float mix0;\nuniform float mix1;\nuniform float mix2;\nuniform float mix3;\n#define height0 0.125\n#define height1 0.375\n#define height2 0.625\n#define height3 0.875\n#endif\n#endif\n\nuniform vec4 ipScalarRangeMin;\nuniform vec4 ipScalarRangeMax;\n\n// declaration for intermixed geometry\n//VTK::ZBuffer::Dec\n\n//=======================================================================\n// global and custom variables (a temporary section before photorealistics rendering module is complete)\nvec3 rayDirVC;\nfloat sampleDistanceISVS;\nfloat sampleDistanceIS;\n\n#define SQRT3 1.7321\n#define INV4PI 0.0796\n#define EPSILON 0.001\n#define PI 3.1415\n#define PI2 9.8696\n\n//=======================================================================\n// Webgl2 specific version of functions\n#if __VERSION__ == 300\n\nuniform highp sampler3D texture1;\n\nvec4 getTextureValue(vec3 pos)\n{\n vec4 tmp = texture(texture1, pos);\n\n #if defined(vtkComponent0ForceNearest) || \\\n defined(vtkComponent1ForceNearest) || \\\n defined(vtkComponent2ForceNearest) || \\\n defined(vtkComponent3ForceNearest)\n vec3 nearestPos = (floor(pos * vec3(volumeDimensions)) + 0.5) / vec3(volumeDimensions);\n vec4 nearestValue = texture(texture1, nearestPos);\n #ifdef vtkComponent0ForceNearest\n tmp[0] = nearestValue[0];\n #endif\n #ifdef vtkComponent1ForceNearest\n tmp[1] = nearestValue[1];\n #endif\n #ifdef vtkComponent2ForceNearest\n tmp[2] = nearestValue[2];\n #endif\n #ifdef vtkComponent3ForceNearest\n tmp[3] = nearestValue[3];\n #endif\n #endif\n\n #ifndef UseIndependentComponents\n #if vtkNumComponents == 1\n tmp.a = tmp.r;\n #endif\n #if vtkNumComponents == 2\n tmp.a = tmp.g;\n #endif\n #if vtkNumComponents == 3\n tmp.a = length(tmp.rgb);\n #endif\n #endif\n\n return tmp;\n}\n\n//=======================================================================\n// WebGL1 specific version of functions\n#else\n\nuniform sampler2D texture1;\n\nuniform float texWidth;\nuniform float texHeight;\nuniform int xreps;\nuniform int xstride;\nuniform int ystride;\n\n// if computing trilinear values from multiple z slices\n#ifdef vtkTrilinearOn\nvec4 getTextureValue(vec3 ijk)\n{\n float zoff = 1.0/float(volumeDimensions.z);\n vec4 val1 = getOneTextureValue(ijk);\n vec4 val2 = getOneTextureValue(vec3(ijk.xy, ijk.z + zoff));\n\n float indexZ = float(volumeDimensions)*ijk.z;\n float zmix = indexZ - floor(indexZ);\n\n return mix(val1, val2, zmix);\n}\n\nvec4 getOneTextureValue(vec3 ijk)\n#else // nearest or fast linear\nvec4 getTextureValue(vec3 ijk)\n#endif\n{\n vec3 tdims = vec3(volumeDimensions);\n\n#ifdef debugtile\n vec2 tpos = vec2(ijk.x, ijk.y);\n vec4 tmp = texture2D(texture1, tpos);\n tmp.a = 1.0;\n\n#else\n int z = int(ijk.z * tdims.z);\n int yz = z / xreps;\n int xz = z - yz*xreps;\n\n int tileWidth = volumeDimensions.x/xstride;\n int tileHeight = volumeDimensions.y/ystride;\n\n xz *= tileWidth;\n yz *= tileHeight;\n\n float ni = float(xz) + (ijk.x*float(tileWidth));\n float nj = float(yz) + (ijk.y*float(tileHeight));\n\n vec2 tpos = vec2(ni/texWidth, nj/texHeight);\n\n vec4 tmp = texture2D(texture1, tpos);\n\n#if vtkNumComponents == 1\n tmp.a = tmp.r;\n#endif\n#if vtkNumComponents == 2\n tmp.g = tmp.a;\n#endif\n#if vtkNumComponents == 3\n tmp.a = length(tmp.rgb);\n#endif\n#endif\n\n return tmp;\n}\n\n// End of Webgl1 specific code\n//=======================================================================\n#endif\n\n//=======================================================================\n// transformation between VC and IS space\n\n// convert vector position from idx to vc\n#if (vtkLightComplexity > 0) || (defined vtkClippingPlanesOn)\nvec3 IStoVC(vec3 posIS){\n vec3 posVC = posIS / vVCToIJK;\n return posVC.x * vPlaneNormal0 +\n posVC.y * vPlaneNormal2 +\n posVC.z * vPlaneNormal4 +\n vOriginVC;\n}\n\n// convert vector position from vc to idx\nvec3 VCtoIS(vec3 posVC){\n posVC = posVC - vOriginVC;\n posVC = vec3(\n dot(posVC, vPlaneNormal0),\n dot(posVC, vPlaneNormal2),\n dot(posVC, vPlaneNormal4));\n return posVC * vVCToIJK;\n}\n#endif\n\n//Rotate vector to view coordinate\n#if (vtkLightComplexity > 0) || (defined vtkGradientOpacityOn)\nvoid rotateToViewCoord(inout vec3 dirIS){\n dirIS.xyz =\n dirIS.x * vPlaneNormal0 +\n dirIS.y * vPlaneNormal2 +\n dirIS.z * vPlaneNormal4;\n}\n\n//Rotate vector to idx coordinate\nvec3 rotateToIDX(vec3 dirVC){\n vec3 dirIS;\n dirIS.xyz = vec3(\n dot(dirVC, vPlaneNormal0),\n dot(dirVC, vPlaneNormal2),\n dot(dirVC, vPlaneNormal4));\n return dirIS;\n}\n#endif\n\n//=======================================================================\n// Given a normal compute the gradient opacity factors\nfloat computeGradientOpacityFactor(\n float normalMag, float goscale, float goshift, float gomin, float gomax)\n{\n return clamp(normalMag * goscale + goshift, gomin, gomax);\n}\n\n//=======================================================================\n// compute the normal and gradient magnitude for a position, uses forward difference\n#if (vtkLightComplexity > 0) || (defined vtkGradientOpacityOn)\n #ifdef vtkClippingPlanesOn\n void adjustClippedVoxelValues(vec3 pos, vec3 texPos[3], inout vec3 g1)\n {\n vec3 g1VC[3];\n for (int i = 0; i < 3; ++i)\n {\n g1VC[i] = IStoVC(texPos[i]);\n }\n vec3 posVC = IStoVC(pos);\n for (int i = 0; i < clip_numPlanes; ++i)\n {\n for (int j = 0; j < 3; ++j)\n {\n if(dot(vec3(vClipPlaneOrigins[i] - g1VC[j].xyz), vClipPlaneNormals[i]) > 0.0)\n {\n g1[j] = 0.0;\n }\n }\n }\n }\n #endif\n\n #ifdef vtkComputeNormalFromOpacity\n vec4 computeDensityNormal(vec3 opacityUCoords[2], float opactityTextureHeight, float gradientOpacity) {\n vec3 opacityG1, opacityG2;\n opacityG1.x = texture2D(otexture, vec2(opacityUCoords[0].x, opactityTextureHeight)).r;\n opacityG1.y = texture2D(otexture, vec2(opacityUCoords[0].y, opactityTextureHeight)).r;\n opacityG1.z = texture2D(otexture, vec2(opacityUCoords[0].z, opactityTextureHeight)).r;\n opacityG2.x = texture2D(otexture, vec2(opacityUCoords[1].x, opactityTextureHeight)).r;\n opacityG2.y = texture2D(otexture, vec2(opacityUCoords[1].y, opactityTextureHeight)).r;\n opacityG2.z = texture2D(otexture, vec2(opacityUCoords[1].z, opactityTextureHeight)).r;\n opacityG1.xyz *= gradientOpacity;\n opacityG2.xyz *= gradientOpacity;\n\n vec4 opacityG = vec4(opacityG1 - opacityG2, 1.0f);\n // divide by spacing\n opacityG.xyz /= vSpacing;\n opacityG.w = length(opacityG.xyz);\n // rotate to View Coords\n rotateToViewCoord(opacityG.xyz);\n if (!all(equal(opacityG.xyz, vec3(0.0)))) {\n return vec4(normalize(opacityG.xyz),opacityG.w);\n } else {\n return vec4(0.0);\n }\n }\n\n vec4 computeNormalForDensity(vec3 pos, vec3 tstep, out vec3 scalarInterp[2], const int opacityComponent)\n {\n vec3 xvec = vec3(tstep.x, 0.0, 0.0);\n vec3 yvec = vec3(0.0, tstep.y, 0.0);\n vec3 zvec = vec3(0.0, 0.0, tstep.z);\n vec3 texPosPVec[3];\n texPosPVec[0] = pos + xvec;\n texPosPVec[1] = pos + yvec;\n texPosPVec[2] = pos + zvec;\n vec3 texPosNVec[3];\n texPosNVec[0] = pos - xvec;\n texPosNVec[1] = pos - yvec;\n texPosNVec[2] = pos - zvec;\n vec3 g1, g2;\n\n scalarInterp[0].x = getTextureValue(texPosPVec[0])[opacityComponent];\n scalarInterp[0].y = getTextureValue(texPosPVec[1])[opacityComponent];\n scalarInterp[0].z = getTextureValue(texPosPVec[2])[opacityComponent];\n scalarInterp[1].x = getTextureValue(texPosNVec[0])[opacityComponent];\n scalarInterp[1].y = getTextureValue(texPosNVec[1])[opacityComponent];\n scalarInterp[1].z = getTextureValue(texPosNVec[2])[opacityComponent];\n\n #ifdef vtkClippingPlanesOn\n adjustClippedVoxelValues(pos, texPosPVec, scalarInterp[0]);\n adjustClippedVoxelValues(pos, texPosNVec, scalarInterp[1]);\n #endif\n vec4 result;\n result.x = scalarInterp[0].x - scalarInterp[1].x;\n result.y = scalarInterp[0].y - scalarInterp[1].y;\n result.z = scalarInterp[0].z - scalarInterp[1].z;\n // divide by spacing\n result.xyz /= vSpacing;\n result.w = length(result.xyz);\n // rotate to View Coords\n rotateToViewCoord(result.xyz);\n if (length(result.xyz) > 0.0) {\n return vec4(normalize(result.xyz),result.w);\n } else {\n return vec4(0.0);\n }\n }\n #endif\n\n // only works with dependent components\n vec4 computeNormal(vec3 pos, vec3 tstep)\n {\n vec3 xvec = vec3(tstep.x, 0.0, 0.0);\n vec3 yvec = vec3(0.0, tstep.y, 0.0);\n vec3 zvec = vec3(0.0, 0.0, tstep.z);\n vec3 texPosPVec[3];\n texPosPVec[0] = pos + xvec;\n texPosPVec[1] = pos + yvec;\n texPosPVec[2] = pos + zvec;\n vec3 texPosNVec[3];\n texPosNVec[0] = pos - xvec;\n texPosNVec[1] = pos - yvec;\n texPosNVec[2] = pos - zvec;\n vec3 g1, g2;\n g1.x = getTextureValue(texPosPVec[0]).a;\n g1.y = getTextureValue(texPosPVec[1]).a;\n g1.z = getTextureValue(texPosPVec[2]).a;\n g2.x = getTextureValue(texPosNVec[0]).a;\n g2.y = getTextureValue(texPosNVec[1]).a;\n g2.z = getTextureValue(texPosNVec[2]).a;\n #ifdef vtkClippingPlanesOn\n adjustClippedVoxelValues(pos, texPosPVec, g1);\n adjustClippedVoxelValues(pos, texPosNVec, g2);\n #endif\n vec4 result;\n result = vec4(g1 - g2, -1.0);\n // divide by spacing\n result.xyz /= vSpacing;\n result.w = length(result.xyz);\n if (result.w > 0.0){\n // rotate to View Coords\n rotateToViewCoord(result.xyz);\n return vec4(normalize(result.xyz),result.w);\n } else {\n return vec4(0.0);\n }\n }\n#endif\n\n#ifdef vtkImageLabelOutlineOn\nvec3 fragCoordToIndexSpace(vec4 fragCoord) {\n vec4 pcPos = vec4(\n (fragCoord.x / vpWidth - vpOffsetX - 0.5) * 2.0,\n (fragCoord.y / vpHeight - vpOffsetY - 0.5) * 2.0,\n (fragCoord.z - 0.5) * 2.0,\n 1.0);\n\n vec4 worldCoord = PCWCMatrix * pcPos;\n vec4 vertex = (worldCoord/worldCoord.w);\n\n vec3 index = (vWCtoIDX * vertex).xyz;\n\n // half voxel fix for labelmapOutline\n return (index + vec3(0.5)) / vec3(volumeDimensions);\n}\n#endif\n\n//=======================================================================\n// compute the normals and gradient magnitudes for a position\n// for independent components\nmat4 computeMat4Normal(vec3 pos, vec4 tValue, vec3 tstep)\n{\n mat4 result;\n vec4 distX = getTextureValue(pos + vec3(tstep.x, 0.0, 0.0)) - tValue;\n vec4 distY = getTextureValue(pos + vec3(0.0, tstep.y, 0.0)) - tValue;\n vec4 distZ = getTextureValue(pos + vec3(0.0, 0.0, tstep.z)) - tValue;\n\n // divide by spacing\n distX /= vSpacing.x;\n distY /= vSpacing.y;\n distZ /= vSpacing.z;\n\n mat3 rot;\n rot[0] = vPlaneNormal0;\n rot[1] = vPlaneNormal2;\n rot[2] = vPlaneNormal4;\n\n#if !defined(vtkComponent0Proportional)\n result[0].xyz = vec3(distX.r, distY.r, distZ.r);\n result[0].a = length(result[0].xyz);\n result[0].xyz *= rot;\n if (result[0].w > 0.0)\n {\n result[0].xyz /= result[0].w;\n }\n#endif\n\n// optionally compute the 2nd component\n#if vtkNumComponents >= 2 && !defined(vtkComponent1Proportional)\n result[1].xyz = vec3(distX.g, distY.g, distZ.g);\n result[1].a = length(result[1].xyz);\n result[1].xyz *= rot;\n if (result[1].w > 0.0)\n {\n result[1].xyz /= result[1].w;\n }\n#endif\n\n// optionally compute the 3rd component\n#if vtkNumComponents >= 3 && !defined(vtkComponent2Proportional)\n result[2].xyz = vec3(distX.b, distY.b, distZ.b);\n result[2].a = length(result[2].xyz);\n result[2].xyz *= rot;\n if (result[2].w > 0.0)\n {\n result[2].xyz /= result[2].w;\n }\n#endif\n\n// optionally compute the 4th component\n#if vtkNumComponents >= 4 && !defined(vtkComponent3Proportional)\n result[3].xyz = vec3(distX.a, distY.a, distZ.a);\n result[3].a = length(result[3].xyz);\n result[3].xyz *= rot;\n if (result[3].w > 0.0)\n {\n result[3].xyz /= result[3].w;\n }\n#endif\n\n return result;\n}\n\n//=======================================================================\n// global shadow - secondary ray\n#if defined(VolumeShadowOn) || defined(localAmbientOcclusionOn)\nfloat random()\n{\n float rand = fract(sin(dot(gl_FragCoord.xy,vec2(12.9898,78.233)))*43758.5453123);\n float jitter=texture2D(jtexture,gl_FragCoord.xy/32.).r;\n uint pcg_state = floatBitsToUint(jitter);\n uint state = pcg_state;\n pcg_state = pcg_state * uint(747796405) + uint(2891336453);\n uint word = ((state >> ((state >> uint(28)) + uint(4))) ^ state) * uint(277803737);\n return (float((((word >> uint(22)) ^ word) >> 1 ))/float(2147483647) + rand)/2.0;\n}\n#endif\n\n#ifdef VolumeShadowOn\n// henyey greenstein phase function\nfloat phase_function(float cos_angle)\n{\n // divide by 2.0 instead of 4pi to increase intensity\n return ((1.0-anisotropy2)/pow(1.0+anisotropy2-2.0*anisotropy*cos_angle, 1.5))/2.0;\n}\n\n// Computes the intersection between a ray and a box\nstruct Hit\n{\n float tmin;\n float tmax;\n};\n\nstruct Ray\n{\n vec3 origin;\n vec3 dir;\n vec3 invDir;\n};\n\nbool BBoxIntersect(vec3 boundMin, vec3 boundMax, const Ray r, out Hit hit)\n{\n vec3 tbot = r.invDir * (boundMin - r.origin);\n vec3 ttop = r.invDir * (boundMax - r.origin);\n vec3 tmin = min(ttop, tbot);\n vec3 tmax = max(ttop, tbot);\n vec2 t = max(tmin.xx, tmin.yz);\n float t0 = max(t.x, t.y);\n t = min(tmax.xx, tmax.yz);\n float t1 = min(t.x, t.y);\n hit.tmin = t0;\n hit.tmax = t1;\n return t1 > max(t0,0.0);\n}\n\n// As BBoxIntersect requires the inverse of the ray coords,\n// this function is used to avoid numerical issues\nvoid safe_0_vector(inout Ray ray)\n{\n if(abs(ray.dir.x) < EPSILON) ray.dir.x = sign(ray.dir.x) * EPSILON;\n if(abs(ray.dir.y) < EPSILON) ray.dir.y = sign(ray.dir.y) * EPSILON;\n if(abs(ray.dir.z) < EPSILON) ray.dir.z = sign(ray.dir.z) * EPSILON;\n}\n\nfloat volume_shadow(vec3 posIS, vec3 lightDirNormIS)\n{\n float shadow = 1.0;\n float opacity = 0.0;\n\n // modify sample distance with a random number between 1.5 and 3.0\n float sampleDistanceISVS_jitter = sampleDistanceISVS * mix(1.5, 3.0, random());\n float opacityPrev = texture2D(otexture, vec2(getTextureValue(posIS).r * oscale0 + oshift0, 0.5)).r;\n\n // in case the first sample near surface has a very tiled light ray, we need to offset start position\n posIS += sampleDistanceISVS_jitter * lightDirNormIS;\n\n // compute the start and end points for the ray\n Ray ray;\n Hit hit;\n ray.origin = posIS;\n ray.dir = lightDirNormIS;\n safe_0_vector(ray);\n ray.invDir = 1.0/ray.dir;\n\n if(!BBoxIntersect(vec3(0.0),vec3(1.0), ray, hit))\n {\n return 1.0;\n }\n float maxdist = hit.tmax;\n\n // interpolate shadow ray length between: 1 unit of sample distance in IS to SQRT3, based on globalIlluminationReach\n float maxgi = mix(sampleDistanceISVS_jitter,SQRT3,giReach);\n maxdist = min(maxdist,maxgi);\n if(maxdist < EPSILON) {\n return 1.0;\n }\n\n float current_dist = 0.0;\n float current_step = length(sampleDistanceISVS_jitter * lightDirNormIS);\n float clamped_step = 0.0;\n\n vec4 scalar = vec4(0.0);\n while(current_dist < maxdist)\n {\n#ifdef vtkClippingPlanesOn\n vec3 posVC = IStoVC(posIS);\n for (int i = 0; i < clip_numPlanes; ++i)\n {\n if (dot(vec3(vClipPlaneOrigins[i] - posVC), vClipPlaneNormals[i]) > 0.0)\n {\n current_dist = maxdist;\n }\n }\n#endif\n scalar = getTextureValue(posIS);\n opacity = texture2D(otexture, vec2(scalar.r * oscale0 + oshift0, 0.5)).r;\n #if defined(vtkGradientOpacityOn) && !defined(UseIndependentComponents)\n vec4 normal = computeNormal(posIS, vec3(1.0/vec3(volumeDimensions)));\n opacity *= computeGradientOpacityFactor(normal.w, goscale0, goshift0, gomin0, gomax0);\n #endif\n shadow *= 1.0 - opacity;\n\n // optimization: early termination\n if (shadow < EPSILON){\n return 0.0;\n }\n\n clamped_step = min(maxdist - current_dist, current_step);\n posIS += clamped_step * lightDirNormIS;\n current_dist += current_step;\n }\n\n return shadow;\n}\n\nvec3 applyShadowRay(vec3 tColor, vec3 posIS, vec3 viewDirectionVC)\n{\n vec3 vertLight = vec3(0.0);\n vec3 secondary_contrib = vec3(0.0);\n // here we assume only positional light, no effect of cones\n for (int i = 0; i < lightNum; i++)\n {\n #if(vtkLightComplexity==3)\n if (lightPositional[i] == 1){\n vertLight = lightPositionVC[i] - IStoVC(posIS);\n }else{\n vertLight = - lightDirectionVC[i];\n }\n #else\n vertLight = - lightDirectionVC[i];\n #endif\n // here we assume achromatic light, only intensity\n float dDotL = dot(viewDirectionVC, normalize(vertLight));\n // isotropic scatter returns 0.5 instead of 1/4pi to increase intensity\n float phase_attenuation = 0.5;\n if (abs(anisotropy) > EPSILON){\n phase_attenuation = phase_function(dDotL);\n }\n float vol_shadow = volume_shadow(posIS, normalize(rotateToIDX(vertLight)));\n secondary_contrib += tColor * vDiffuse * lightColor[i] * vol_shadow * phase_attenuation;\n secondary_contrib += tColor * vAmbient;\n }\n return secondary_contrib;\n}\n#endif\n\n//=======================================================================\n// local ambient occlusion\n#ifdef localAmbientOcclusionOn\nvec3 sample_direction_uniform(int i)\n{\n float rand = random() * 0.5;\n float theta = PI2 * (kernelSample[i][0] + rand);\n float phi = acos(2.0 * (kernelSample[i][1] + rand) -1.0) / 2.5;\n return normalize(vec3(cos(theta)*sin(phi), sin(theta)*sin(phi), cos(phi)));\n}\n\n// return a matrix that transform startDir into z axis; startDir should be normalized\nmat3 zBaseRotationalMatrix(vec3 startDir){\n vec3 axis = cross(startDir, vec3(0.0,0.0,1.0));\n float cosA = startDir.z;\n float k = 1.0 / (1.0 + cosA);\n mat3 matrix = mat3((axis.x * axis.x * k) + cosA, (axis.y * axis.x * k) - axis.z, (axis.z * axis.x * k) + axis.y,\n (axis.x * axis.y * k) + axis.z, (axis.y * axis.y * k) + cosA, (axis.z * axis.y * k) - axis.x,\n (axis.x * axis.z * k) - axis.y, (axis.y * axis.z * k) + axis.x, (axis.z * axis.z * k) + cosA);\n return matrix;\n}\n\nfloat computeLAO(vec3 posIS, float op, vec3 lightDir, vec4 normal){\n // apply LAO only at selected locations, otherwise return full brightness\n if (normal.w > 0.0 && op > 0.05){\n float total_transmittance = 0.0;\n mat3 inverseRotateBasis = inverse(zBaseRotationalMatrix(normalize(-normal.xyz)));\n vec3 currPos, randomDirStep;\n float weight, transmittance, opacity;\n for (int i = 0; i < kernelSize; i++)\n {\n randomDirStep = inverseRotateBasis * sample_direction_uniform(i) * sampleDistanceIS;\n weight = 1.0 - dot(normalize(lightDir), normalize(randomDirStep));\n currPos = posIS;\n transmittance = 1.0;\n for (int j = 0; j < kernelRadius ; j++){\n currPos += randomDirStep;\n // check if it's at clipping plane, if so return full brightness\n if (all(greaterThan(currPos, vec3(EPSILON))) && all(lessThan(currPos,vec3(1.0-EPSILON)))){\n opacity = texture2D(otexture, vec2(getTextureValue(currPos).r * oscale0 + oshift0, 0.5)).r;\n #ifdef vtkGradientOpacityOn\n opacity *= computeGradientOpacityFactor(normal.w, goscale0, goshift0, gomin0, gomax0);\n #endif\n transmittance *= 1.0 - opacity;\n }\n else{\n break;\n }\n }\n total_transmittance += transmittance / float(kernelRadius) * weight;\n\n // early termination if fully translucent\n if (total_transmittance > 1.0 - EPSILON){\n return 1.0;\n }\n }\n // average transmittance and reduce variance\n return clamp(total_transmittance / float(kernelSize), 0.3, 1.0);\n } else {\n return 1.0;\n }\n}\n#endif\n\n//=======================================================================\n// surface light contribution\n#if vtkLightComplexity > 0\n void applyLighting(inout vec3 tColor, vec4 normal)\n {\n vec3 diffuse = vec3(0.0, 0.0, 0.0);\n vec3 specular = vec3(0.0, 0.0, 0.0);\n float df, sf = 0.0;\n for (int i = 0; i < lightNum; i++){\n df = abs(dot(normal.rgb, -lightDirectionVC[i]));\n diffuse += df * lightColor[i];\n sf = pow( abs(dot(lightHalfAngleVC[i],normal.rgb)), vSpecularPower);\n specular += sf * lightColor[i];\n }\n tColor.rgb = tColor.rgb*(diffuse*vDiffuse + vAmbient) + specular*vSpecular;\n }\n #ifdef SurfaceShadowOn\n #if vtkLightComplexity < 3\n vec3 applyLightingDirectional(vec3 posIS, vec4 tColor, vec4 normal)\n {\n // everything in VC\n vec3 diffuse = vec3(0.0);\n vec3 specular = vec3(0.0);\n #ifdef localAmbientOcclusionOn\n vec3 ambient = vec3(0.0);\n #endif\n vec3 vertLightDirection;\n for (int i = 0; i < lightNum; i++){\n float ndotL,vdotR;\n vertLightDirection = lightDirectionVC[i];\n ndotL = dot(normal.xyz, vertLightDirection);\n if (ndotL < 0.0 && twoSidedLighting)\n {\n ndotL = -ndotL;\n }\n if (ndotL > 0.0)\n {\n diffuse += ndotL * lightColor[i];\n //specular\n vdotR = dot(-rayDirVC, normalize(2.0 * ndotL * -normal.xyz + vertLightDirection));\n if (vdotR > 0.0)\n {\n specular += pow(vdotR, vSpecularPower) * lightColor[i];\n }\n }\n #ifdef localAmbientOcclusionOn\n ambient += computeLAO(posIS, tColor.a, vertLightDirection, normal);\n #endif\n }\n #ifdef localAmbientOcclusionOn\n return tColor.rgb * (diffuse * vDiffuse + vAmbient * ambient) + specular*vSpecular;\n #else\n return tColor.rgb * (diffuse * vDiffuse + vAmbient) + specular*vSpecular;\n #endif\n }\n #else\n vec3 applyLightingPositional(vec3 posIS, vec4 tColor, vec4 normal, vec3 posVC)\n {\n // everything in VC\n vec3 diffuse = vec3(0.0);\n vec3 specular = vec3(0.0);\n #ifdef localAmbientOcclusionOn\n vec3 ambient = vec3(0.0);\n #endif\n vec3 vertLightDirection;\n for (int i = 0; i < lightNum; i++){\n float distance,attenuation,ndotL,vdotR;\n vec3 lightDir;\n if (lightPositional[i] == 1){\n lightDir = lightDirectionVC[i];\n vertLightDirection = posVC - lightPositionVC[i];\n distance = length(vertLightDirection);\n vertLightDirection = normalize(vertLightDirection);\n attenuation = 1.0 / (lightAttenuation[i].x\n + lightAttenuation[i].y * distance\n + lightAttenuation[i].z * distance * distance);\n // per OpenGL standard cone angle is 90 or less for a spot light\n if (lightConeAngle[i] <= 90.0){\n float coneDot = dot(vertLightDirection, lightDir);\n if (coneDot >= cos(radians(lightConeAngle[i]))){ // if inside cone\n attenuation = attenuation * pow(coneDot, lightExponent[i]);\n }\n else {\n attenuation = 0.0;\n }\n }\n ndotL = dot(normal.xyz, vertLightDirection);\n if (ndotL < 0.0 && twoSidedLighting)\n {\n ndotL = -ndotL;\n }\n if (ndotL > 0.0)\n {\n diffuse += ndotL * attenuation * lightColor[i];\n //specular\n vdotR = dot(-rayDirVC, normalize(2.0 * ndotL * -normal.xyz + vertLightDirection));\n if (vdotR > 0.0)\n {\n specular += pow(vdotR, vSpecularPower) * attenuation * lightColor[i];\n }\n }\n #ifdef localAmbientOcclusionOn\n ambient += computeLAO(posIS, tColor.a, vertLightDirection, normal);\n #endif\n } else {\n vertLightDirection = lightDirectionVC[i];\n ndotL = dot(normal.xyz, vertLightDirection);\n if (ndotL < 0.0 && twoSidedLighting)\n {\n ndotL = -ndotL;\n }\n if (ndotL > 0.0)\n {\n diffuse += ndotL * lightColor[i];\n //specular\n vdotR = dot(-rayDirVC, normalize(2.0 * ndotL * -normal.xyz + vertLightDirection));\n if (vdotR > 0.0)\n {\n specular += pow(vdotR, vSpecularPower) * lightColor[i];\n }\n }\n #ifdef localAmbientOcclusionOn\n ambient += computeLAO(posIS, tColor.a, vertLightDirection, normal);\n #endif\n }\n }\n #ifdef localAmbientOcclusionOn\n return tColor.rgb * (diffuse * vDiffuse + vAmbient * ambient) + specular*vSpecular;\n #else\n return tColor.rgb * (diffuse * vDiffuse + vAmbient) + specular*vSpecular;\n #endif\n }\n #endif\n #endif\n#endif\n\n// LAO of surface shadows and volume shadows only work with dependent components\nvec3 applyAllLightning(vec3 tColor, float alpha, vec3 posIS, vec4 normalLight) {\n #if vtkLightComplexity > 0\n // surface shadows if needed\n #ifdef SurfaceShadowOn\n #if vtkLightComplexity < 3\n vec3 tColorS = applyLightingDirectional(posIS, vec4(tColor, alpha), normalLight);\n #else\n vec3 tColorS = applyLightingPositional(posIS, vec4(tColor, alpha), normalLight, IStoVC(posIS));\n #endif\n #endif\n\n // volume shadows if needed\n #ifdef VolumeShadowOn\n vec3 tColorVS = applyShadowRay(tColor, posIS, rayDirVC);\n #endif\n\n // merge\n #ifdef VolumeShadowOn\n #ifdef SurfaceShadowOn\n // surface shadows + volumetric shadows\n float vol_coef = volumetricScatteringBlending * (1.0 - alpha / 2.0) * (1.0 - atan(normalLight.w) * INV4PI);\n tColor = (1.0-vol_coef) * tColorS + vol_coef * tColorVS;\n #else\n // volumetric shadows only\n tColor = tColorVS;\n #endif\n #else\n #ifdef SurfaceShadowOn\n // surface shadows only\n tColor = tColorS;\n #else\n // no shadows\n applyLighting(tColor, normal3);\n #endif\n #endif\n #endif\n return tColor;\n}\n\n//=======================================================================\n// Given a texture value compute the color and opacity\n//\nvec4 getColorForValue(vec4 tValue, vec3 posIS, vec3 tstep)\n{\n#ifdef vtkImageLabelOutlineOn\n vec3 centerPosIS = fragCoordToIndexSpace(gl_FragCoord); // pos in texture space\n vec4 centerValue = getTextureValue(centerPosIS);\n bool pixelOnBorder = false;\n vec4 tColor = texture2D(ctexture, vec2(centerValue.r * cscale0 + cshift0, 0.5));\n\n // Get alpha of segment from opacity function.\n tColor.a = texture2D(otexture, vec2(centerValue.r * oscale0 + oshift0, 0.5)).r;\n\n int segmentIndex = int(centerValue.r * 255.0);\n \n // Use texture sampling for outlineThickness\n float textureCoordinate = float(segmentIndex - 1) / 1024.0;\n float textureValue = texture2D(ttexture, vec2(textureCoordinate, 0.5)).r;\n\n int actualThickness = int(textureValue * 255.0);\n\n\n // If it is the background (segment index 0), we should quickly bail out. \n // Previously, this was determined by tColor.a, which was incorrect as it\n // prevented the outline from appearing when the fill is 0.\n if (segmentIndex == 0){\n return vec4(0, 0, 0, 0);\n }\n\n // Only perform outline check on fragments rendering voxels that aren't invisible.\n // Saves a bunch of needless checks on the background.\n // TODO define epsilon when building shader?\n for (int i = -actualThickness; i <= actualThickness; i++) {\n for (int j = -actualThickness; j <= actualThickness; j++) {\n if (i == 0 || j == 0) {\n continue;\n }\n\n vec4 neighborPixelCoord = vec4(gl_FragCoord.x + float(i),\n gl_FragCoord.y + float(j),\n gl_FragCoord.z, gl_FragCoord.w);\n\n vec3 neighborPosIS = fragCoordToIndexSpace(neighborPixelCoord);\n vec4 value = getTextureValue(neighborPosIS);\n\n // If any of my neighbours are not the same value as I\n // am, this means I am on the border of the segment.\n // We can break the loops\n if (any(notEqual(value, centerValue))) {\n pixelOnBorder = true;\n break;\n }\n }\n\n if (pixelOnBorder == true) {\n break;\n }\n }\n\n // If I am on the border, I am displayed at full opacity\n if (pixelOnBorder == true) {\n tColor.a = outlineOpacity;\n }\n\n return tColor;\n\n#else\n // compute the normal and gradient magnitude if needed\n // We compute it as a vec4 if possible otherwise a mat4\n\n #ifdef UseIndependentComponents\n // sample textures\n vec3 tColor0 = texture2D(ctexture, vec2(tValue.r * cscale0 + cshift0, height0)).rgb;\n float pwfValue0 = texture2D(otexture, vec2(tValue.r * oscale0 + oshift0, height0)).r;\n\n #if vtkNumComponents > 1\n vec3 tColor1 = texture2D(ctexture, vec2(tValue.g * cscale1 + cshift1, height1)).rgb;\n float pwfValue1 = texture2D(otexture, vec2(tValue.g * oscale1 + oshift1, height1)).r;\n\n #if vtkNumComponents > 2\n vec3 tColor2 = texture2D(ctexture, vec2(tValue.b * cscale2 + cshift2, height2)).rgb;\n float pwfValue2 = texture2D(otexture, vec2(tValue.b * oscale2 + oshift2, height2)).r;\n\n #if vtkNumComponents > 3\n vec3 tColor3 = texture2D(ctexture, vec2(tValue.a * cscale3 + cshift3, height3)).rgb;\n float pwfValue3 = texture2D(otexture, vec2(tValue.a * oscale3 + oshift3, height3)).r;\n #endif\n #endif\n #endif\n\n #if !defined(vtkCustomComponentsColorMix)\n // default path for component color mix\n\n // compute the normal vectors as needed\n #if (vtkLightComplexity > 0) || defined(vtkGradientOpacityOn)\n mat4 normalMat = computeMat4Normal(posIS, tValue, tstep);\n #endif\n\n // compute gradient opacity factors as needed\n vec4 goFactor = vec4(1.0, 1.0 ,1.0 ,1.0);\n #if defined(vtkGradientOpacityOn)\n #if !defined(vtkComponent0Proportional)\n goFactor.x =\n computeGradientOpacityFactor(normalMat[0].a, goscale0, goshift0, gomin0, gomax0);\n #endif\n #if vtkNumComponents > 1\n #if !defined(vtkComponent1Proportional)\n goFactor.y =\n computeGradientOpacityFactor(normalMat[1].a, goscale1, goshift1, gomin1, gomax1);\n #endif\n #if vtkNumComponents > 2\n #if !defined(vtkComponent2Proportional)\n goFactor.z =\n computeGradientOpacityFactor(normalMat[2].a, goscale2, goshift2, gomin2, gomax2);\n #endif\n #if vtkNumComponents > 3\n #if !defined(vtkComponent3Proportional)\n goFactor.w =\n computeGradientOpacityFactor(normalMat[3].a, goscale3, goshift3, gomin3, gomax3);\n #endif\n #endif\n #endif\n #endif\n #endif\n\n // process color and opacity for each component\n #if !defined(vtkComponent0Proportional)\n float alpha = goFactor.x*mix0*pwfValue0;\n #if vtkLightComplexity > 0\n applyLighting(tColor0, normalMat[0]);\n #endif\n #else\n tColor0 *= pwfValue0;\n float alpha = mix(pwfValue0, 1.0, (1.0 - mix0));\n #endif\n\n #if vtkNumComponents > 1\n #if !defined(vtkComponent1Proportional)\n alpha += goFactor.y*mix1*pwfValue1;\n #if vtkLightComplexity > 0\n applyLighting(tColor1, normalMat[1]);\n #endif\n #else\n tColor1 *= pwfValue1;\n alpha *= mix(pwfValue1, 1.0, (1.0 - mix1));\n #endif\n\n #if vtkNumComponents > 2\n #if !defined(vtkComponent2Proportional)\n alpha += goFactor.z*mix2*pwfValue2;\n #if vtkLightComplexity > 0\n applyLighting(tColor2, normalMat[2]);\n #endif\n #else\n tColor2 *= pwfValue2;\n alpha *= mix(pwfValue2, 1.0, (1.0 - mix2));\n #endif\n #endif\n\n #if vtkNumComponents > 3\n #if !defined(vtkComponent3Proportional)\n alpha += goFactor.w*mix3*pwfValue3;\n #if vtkLightComplexity > 0\n applyLighting(tColor3, normalMat[3]);\n #endif\n #else\n tColor3 *= pwfValue3;\n alpha *= mix(pwfValue3, 1.0, (1.0 - mix3));\n #endif\n #endif\n #endif\n\n // perform final independent blend\n vec3 tColor = mix0 * tColor0;\n #if vtkNumComponents > 1\n tColor += mix1 * tColor1;\n #if vtkNumComponents > 2\n tColor += mix2 * tColor2;\n #if vtkNumComponents > 3\n tColor += mix3 * tColor3;\n #endif\n #endif\n #endif\n\n return vec4(tColor, alpha);\n #else\n /*\n * Mix the color information from all the independent components to get a single rgba output\n * Gradient opactity factors and normals are not computed\n *\n * You can compute these using:\n * - computeMat4Normal: always available, compute normal only for non proportional components, used by default independent component mix\n * - computeDensityNormal & computeNormalForDensity: available if ((LightComplexity > 0) || GradientOpacityOn) && ComputeNormalFromOpacity),\n * used by dependent component color mix, see code for Additive preset in OpenGl/VolumeMapper\n * - computeGradientOpacityFactor: always available, used in a lot of places\n *\n * Using applyAllLightning() is advised for shading but some features don't work well with it (volume shadows, LAO)\n * mix0, mix1, ... are defined for each component that is used and correspond to the componentWeight\n */\n //VTK::CustomComponentsColorMix::Impl\n #endif\n #else\n // dependent components\n\n // compute normal if needed\n #if (vtkLightComplexity > 0) || defined(vtkGradientOpacityOn)\n // use component 3 of the opacity texture as getTextureValue() sets alpha to the opacity value\n #ifdef vtkComputeNormalFromOpacity\n vec3 scalarInterp[2];\n vec4 normal0 = computeNormalForDensity(posIS, tstep, scalarInterp, 3);\n #else\n vec4 normal0 = computeNormal(posIS, tstep);\n #endif\n #endif\n\n // compute gradient opacity factor enabled\n #if defined(vtkGradientOpacityOn)\n float gradientOpacity = computeGradientOpacityFactor(normal0.a, goscale0, goshift0, gomin0, gomax0);\n #else\n const float gradientOpacity = 1.0;\n #endif\n\n // get color and opacity\n #if vtkNumComponents == 1\n vec3 tColor = texture2D(ctexture, vec2(tValue.r * cscale0 + cshift0, 0.5)).rgb;\n float alpha = gradientOpacity*texture2D(otexture, vec2(tValue.r * oscale0 + oshift0, 0.5)).r;\n if (alpha < EPSILON){\n return vec4(0.0);\n }\n #endif\n #if vtkNumComponents == 2\n vec3 tColor = vec3(tValue.r * cscale0 + cshift0);\n float alpha = gradientOpacity*texture2D(otexture, vec2(tValue.a * oscale1 + oshift1, 0.5)).r;\n #endif\n #if vtkNumComponents == 3\n vec3 tColor;\n tColor.r = tValue.r * cscale0 + cshift0;\n tColor.g = tValue.g * cscale1 + cshift1;\n tColor.b = tValue.b * cscale2 + cshift2;\n float alpha = gradientOpacity*texture2D(otexture, vec2(tValue.a * oscale0 + oshift0, 0.5)).r;\n #endif\n #if vtkNumComponents == 4\n vec3 tColor;\n tColor.r = tValue.r * cscale0 + cshift0;\n tColor.g = tValue.g * cscale1 + cshift1;\n tColor.b = tValue.b * cscale2 + cshift2;\n float alpha = gradientOpacity*texture2D(otexture, vec2(tValue.a * oscale3 + oshift3, 0.5)).r;\n #endif\n\n // lighting\n #if (vtkLightComplexity > 0)\n #ifdef vtkComputeNormalFromOpacity\n vec4 normalLight;\n if (!all(equal(normal0, vec4(0.0)))) {\n scalarInterp[0] = scalarInterp[0] * oscale0 + oshift0;\n scalarInterp[1] = scalarInterp[1] * oscale0 + oshift0;\n normalLight = computeDensityNormal(scalarInterp, 0.5, gradientOpacity);\n if (all(equal(normalLight, vec4(0.0)))) {\n normalLight = normal0;\n }\n }\n #else\n vec4 normalLight = normal0;\n #endif\n tColor = applyAllLightning(tColor, alpha, posIS, normalLight);\n #endif\n\n return vec4(tColor, alpha);\n #endif // dependent\n#endif\n}\n\nbool valueWithinScalarRange(vec4 val, vec4 min, vec4 max) {\n bool withinRange = false;\n #if vtkNumComponents == 1\n if (val.r >= min.r && val.r <= max.r) {\n withinRange = true;\n }\n #else\n #ifdef UseIndependentComponents\n #if vtkNumComponents == 2\n if (val.r >= min.r && val.r <= max.r &&\n val.g >= min.g && val.g <= max.g) {\n withinRange = true;\n }\n #else\n if (all(greaterThanEqual(val, ipScalarRangeMin)) &&\n all(lessThanEqual(val, ipScalarRangeMax))) {\n withinRange = true;\n }\n #endif\n #endif\n #endif\n return withinRange;\n}\n\n//=======================================================================\n// Apply the specified blend mode operation along the ray's path.\n//\nvoid applyBlend(vec3 posIS, vec3 endIS, vec3 tdims)\n{\n vec3 tstep = 1.0/tdims;\n\n // start slightly inside and apply some jitter\n vec3 delta = endIS - posIS;\n vec3 stepIS = normalize(delta)*sampleDistanceIS;\n float raySteps = length(delta)/sampleDistanceIS;\n\n // avoid 0.0 jitter\n float jitter = 0.01 + 0.99*texture2D(jtexture, gl_FragCoord.xy/32.0).r;\n float stepsTraveled = jitter;\n\n // local vars for the loop\n vec4 color = vec4(0.0, 0.0, 0.0, 0.0);\n vec4 tValue;\n vec4 tColor;\n\n // if we have less than one step then pick the middle point\n // as our value\n // if (raySteps <= 1.0)\n // {\n // posIS = (posIS + endIS)*0.5;\n // }\n\n // Perform initial step at the volume boundary\n // compute the scalar\n tValue = getTextureValue(posIS);\n\n #if vtkBlendMode == 0 // COMPOSITE_BLEND\n // now map through opacity and color\n tColor = getColorForValue(tValue, posIS, tstep);\n\n // handle very thin volumes\n if (raySteps <= 1.0)\n {\n tColor.a = 1.0 - pow(1.0 - tColor.a, raySteps);\n gl_FragData[0] = tColor;\n return;\n }\n\n tColor.a = 1.0 - pow(1.0 - tColor.a, jitter);\n color = vec4(tColor.rgb*tColor.a, tColor.a);\n posIS += (jitter*stepIS);\n\n for (int i = 0; i < //VTK::MaximumSamplesValue ; ++i)\n {\n if (stepsTraveled + 1.0 >= raySteps) { break; }\n\n // compute the scalar\n tValue = getTextureValue(posIS);\n\n // now map through opacity and color\n tColor = getColorForValue(tValue, posIS, tstep);\n\n float mix = (1.0 - color.a);\n\n // this line should not be needed but nvidia seems to not handle\n // the break correctly on windows/chrome 58 angle\n //mix = mix * sign(max(raySteps - stepsTraveled - 1.0, 0.0));\n\n color = color + vec4(tColor.rgb*tColor.a, tColor.a)*mix;\n stepsTraveled++;\n posIS += stepIS;\n if (color.a > 0.99) { color.a = 1.0; break; }\n }\n\n if (color.a < 0.99 && (raySteps - stepsTraveled) > 0.0)\n {\n posIS = endIS;\n\n // compute the scalar\n tValue = getTextureValue(posIS);\n\n // now map through opacity and color\n tColor = getColorForValue(tValue, posIS, tstep);\n tColor.a = 1.0 - pow(1.0 - tColor.a, raySteps - stepsTraveled);\n\n float mix = (1.0 - color.a);\n color = color + vec4(tColor.rgb*tColor.a, tColor.a)*mix;\n }\n\n gl_FragData[0] = vec4(color.rgb/color.a, color.a);\n #endif\n #if vtkBlendMode == 1 || vtkBlendMode == 2\n // MAXIMUM_INTENSITY_BLEND || MINIMUM_INTENSITY_BLEND\n // Find maximum/minimum intensity along the ray.\n\n // Define the operation we will use (min or max)\n #if vtkBlendMode == 1\n #define OP max\n #else\n #define OP min\n #endif\n\n // If the clipping range is shorter than the sample distance\n // we can skip the sampling loop along the ray.\n if (raySteps <= 1.0)\n {\n gl_FragData[0] = getColorForValue(tValue, posIS, tstep);\n return;\n }\n\n vec4 value = tValue;\n posIS += (jitter*stepIS);\n\n // Sample along the ray until MaximumSamplesValue,\n // ending slightly inside the total distance\n for (int i = 0; i < //VTK::MaximumSamplesValue ; ++i)\n {\n // If we have reached the last step, break\n if (stepsTraveled + 1.0 >= raySteps) { break; }\n\n // compute the scalar\n tValue = getTextureValue(posIS);\n\n // Update the maximum value if necessary\n value = OP(tValue, value);\n\n // Otherwise, continue along the ray\n stepsTraveled++;\n posIS += stepIS;\n }\n\n // Perform the last step along the ray using the\n // residual distance\n posIS = endIS;\n tValue = getTextureValue(posIS);\n value = OP(tValue, value);\n\n // Now map through opacity and color\n gl_FragData[0] = getColorForValue(value, posIS, tstep);\n #endif\n #if vtkBlendMode == 3 || vtkBlendMode == 4 //AVERAGE_INTENSITY_BLEND || ADDITIVE_BLEND\n vec4 sum = vec4(0.);\n\n if (valueWithinScalarRange(tValue, ipScalarRangeMin, ipScalarRangeMax)) {\n sum += tValue;\n }\n\n if (raySteps <= 1.0) {\n gl_FragData[0] = getColorForValue(sum, posIS, tstep);\n return;\n }\n\n posIS += (jitter*stepIS);\n\n // Sample along the ray until MaximumSamplesValue,\n // ending slightly inside the total distance\n for (int i = 0; i < //VTK::MaximumSamplesValue ; ++i)\n {\n // If we have reached the last step, break\n if (stepsTraveled + 1.0 >= raySteps) { break; }\n\n // compute the scalar\n tValue = getTextureValue(posIS);\n\n // One can control the scalar range by setting the AverageIPScalarRange to disregard scalar values, not in the range of interest, from the average computation.\n // Notes:\n // - We are comparing all values in the texture to see if any of them\n // are outside of the scalar range. In the future we might want to allow\n // scalar ranges for each component.\n if (valueWithinScalarRange(tValue, ipScalarRangeMin, ipScalarRangeMax)) {\n // Sum the values across each step in the path\n sum += tValue;\n }\n stepsTraveled++;\n posIS += stepIS;\n }\n\n // Perform the last step along the ray using the\n // residual distance\n posIS = endIS;\n\n // compute the scalar\n tValue = getTextureValue(posIS);\n\n // One can control the scalar range by setting the IPScalarRange to disregard scalar values, not in the range of interest, from the average computation\n if (valueWithinScalarRange(tValue, ipScalarRangeMin, ipScalarRangeMax)) {\n sum += tValue;\n\n stepsTraveled++;\n }\n\n #if vtkBlendMode == 3 // Average\n sum /= vec4(stepsTraveled, stepsTraveled, stepsTraveled, 1.0);\n #endif\n\n gl_FragData[0] = getColorForValue(sum, posIS, tstep);\n #endif\n #if vtkBlendMode == 5 // RADON\n float normalizedRayIntensity = 1.0;\n\n // handle very thin volumes\n if (raySteps <= 1.0)\n {\n tValue = getTextureValue(posIS);\n normalizedRayIntensity = normalizedRayIntensity - sampleDistance*texture2D(otexture, vec2(tValue.r * oscale0 + oshift0, 0.5)).r;\n gl_FragData[0] = texture2D(ctexture, vec2(normalizedRayIntensity, 0.5));\n return;\n }\n\n posIS += (jitter*stepIS);\n\n for (int i = 0; i < //VTK::MaximumSamplesValue ; ++i)\n {\n if (stepsTraveled + 1.0 >= raySteps) { break; }\n\n // compute the scalar value\n tValue = getTextureValue(posIS);\n\n // Convert scalar value to normalizedRayIntensity coefficient and accumulate normalizedRayIntensity\n normalizedRayIntensity = normalizedRayIntensity - sampleDistance*texture2D(otexture, vec2(tValue.r * oscale0 + oshift0, 0.5)).r;\n\n posIS += stepIS;\n stepsTraveled++;\n }\n\n // map normalizedRayIntensity to color\n gl_FragData[0] = texture2D(ctexture, vec2(normalizedRayIntensity , 0.5));\n\n #endif\n}\n\n//=======================================================================\n// Compute a new start and end point for a given ray based\n// on the provided bounded clipping plane (aka a rectangle)\nvoid getRayPointIntersectionBounds(\n vec3 rayPos, vec3 rayDir,\n vec3 planeDir, float planeDist,\n inout vec2 tbounds, vec3 vPlaneX, vec3 vPlaneY,\n float vSize1, float vSize2)\n{\n float result = dot(rayDir, planeDir);\n if (abs(result) < 1e-6)\n {\n return;\n }\n result = -1.0 * (dot(rayPos, planeDir) + planeDist) / result;\n vec3 xposVC = rayPos + rayDir*result;\n vec3 vxpos = xposVC - vOriginVC;\n vec2 vpos = vec2(\n dot(vxpos, vPlaneX),\n dot(vxpos, vPlaneY));\n\n // on some apple nvidia systems this does not work\n // if (vpos.x < 0.0 || vpos.x > vSize1 ||\n // vpos.y < 0.0 || vpos.y > vSize2)\n // even just\n // if (vpos.x < 0.0 || vpos.y < 0.0)\n // fails\n // so instead we compute a value that represents in and out\n //and then compute the return using this value\n float xcheck = max(0.0, vpos.x * (vpos.x - vSize1)); // 0 means in bounds\n float check = sign(max(xcheck, vpos.y * (vpos.y - vSize2))); // 0 means in bounds, 1 = out\n\n tbounds = mix(\n vec2(min(tbounds.x, result), max(tbounds.y, result)), // in value\n tbounds, // out value\n check); // 0 in 1 out\n}\n\n//=======================================================================\n// given a\n// - ray direction (rayDir)\n// - starting point (vertexVCVSOutput)\n// - bounding planes of the volume\n// - optionally depth buffer values\n// - far clipping plane\n// compute the start/end distances of the ray we need to cast\nvec2 computeRayDistances(vec3 rayDir, vec3 tdims)\n{\n vec2 dists = vec2(100.0*camFar, -1.0);\n\n vec3 vSize = vSpacing*tdims;\n\n // all this is in View Coordinates\n getRayPointIntersectionBounds(vertexVCVSOutput, rayDir,\n vPlaneNormal0, vPlaneDistance0, dists, vPlaneNormal2, vPlaneNormal4,\n vSize.y, vSize.z);\n getRayPointIntersectionBounds(vertexVCVSOutput, rayDir,\n vPlaneNormal1, vPlaneDistance1, dists, vPlaneNormal2, vPlaneNormal4,\n vSize.y, vSize.z);\n getRayPointIntersectionBounds(vertexVCVSOutput, rayDir,\n vPlaneNormal2, vPlaneDistance2, dists, vPlaneNormal0, vPlaneNormal4,\n vSize.x, vSize.z);\n getRayPointIntersectionBounds(vertexVCVSOutput, rayDir,\n vPlaneNormal3, vPlaneDistance3, dists, vPlaneNormal0, vPlaneNormal4,\n vSize.x, vSize.z);\n getRayPointIntersectionBounds(vertexVCVSOutput, rayDir,\n vPlaneNormal4, vPlaneDistance4, dists, vPlaneNormal0, vPlaneNormal2,\n vSize.x, vSize.y);\n getRayPointIntersectionBounds(vertexVCVSOutput, rayDir,\n vPlaneNormal5, vPlaneDistance5, dists, vPlaneNormal0, vPlaneNormal2,\n vSize.x, vSize.y);\n\n //VTK::ClipPlane::Impl\n\n // do not go behind front clipping plane\n dists.x = max(0.0,dists.x);\n\n // do not go PAST far clipping plane\n float farDist = -camThick/rayDir.z;\n dists.y = min(farDist,dists.y);\n\n // Do not go past the zbuffer value if set\n // This is used for intermixing opaque geometry\n //VTK::ZBuffer::Impl\n\n return dists;\n}\n\n//=======================================================================\n// Compute the index space starting position (pos) and end\n// position\n//\nvoid computeIndexSpaceValues(out vec3 pos, out vec3 endPos, vec3 rayDir, vec2 dists)\n{\n // compute starting and ending values in volume space\n pos = vertexVCVSOutput + dists.x*rayDir;\n pos = pos - vOriginVC;\n // convert to volume basis and origin\n pos = vec3(\n dot(pos, vPlaneNormal0),\n dot(pos, vPlaneNormal2),\n dot(pos, vPlaneNormal4));\n\n endPos = vertexVCVSOutput + dists.y*rayDir;\n endPos = endPos - vOriginVC;\n endPos = vec3(\n dot(endPos, vPlaneNormal0),\n dot(endPos, vPlaneNormal2),\n dot(endPos, vPlaneNormal4));\n\n float delta = length(endPos - pos);\n\n pos *= vVCToIJK;\n endPos *= vVCToIJK;\n\n float delta2 = length(endPos - pos);\n sampleDistanceIS = sampleDistance*delta2/delta;\n #ifdef VolumeShadowOn\n sampleDistanceISVS = sampleDistanceIS * volumeShadowSamplingDistFactor;\n #endif\n}\n\nvoid main()\n{\n\n if (cameraParallel == 1)\n {\n // Camera is parallel, so the rayDir is just the direction of the camera.\n rayDirVC = vec3(0.0, 0.0, -1.0);\n } else {\n // camera is at 0,0,0 so rayDir for perspective is just the vc coord\n rayDirVC = normalize(vertexVCVSOutput);\n }\n\n vec3 tdims = vec3(volumeDimensions);\n\n // compute the start and end points for the ray\n vec2 rayStartEndDistancesVC = computeRayDistances(rayDirVC, tdims);\n\n // do we need to composite? aka does the ray have any length\n // If not, bail out early\n if (rayStartEndDistancesVC.y <= rayStartEndDistancesVC.x)\n {\n discard;\n }\n\n // IS = Index Space\n vec3 posIS;\n vec3 endIS;\n computeIndexSpaceValues(posIS, endIS, rayDirVC, rayStartEndDistancesVC);\n\n // Perform the blending operation along the ray\n applyBlend(posIS, endIS, tdims);\n}\n";
|
|
14944
14940
|
|
|
14945
14941
|
|
|
14946
14942
|
|
|
@@ -26615,6 +26611,9 @@ function loadImageFromImageLoader(imageId, options) {
|
|
|
26615
26611
|
return imageLoadObject;
|
|
26616
26612
|
}
|
|
26617
26613
|
function loadImageFromCacheOrVolume(imageId, options) {
|
|
26614
|
+
if (options.ignoreCache) {
|
|
26615
|
+
return loadImageFromImageLoader(imageId, options);
|
|
26616
|
+
}
|
|
26618
26617
|
let imageLoadObject = esm_cache_cache.getImageLoadObject(imageId);
|
|
26619
26618
|
if (imageLoadObject !== undefined) {
|
|
26620
26619
|
return imageLoadObject;
|
|
@@ -29161,10 +29160,14 @@ function calculateViewportsSpatialRegistration(viewport1, viewport2) {
|
|
|
29161
29160
|
function getViewportImageCornersInWorld(viewport) {
|
|
29162
29161
|
const { imageData, dimensions } = viewport.getImageData();
|
|
29163
29162
|
const { canvas } = viewport;
|
|
29163
|
+
const ratio = window.devicePixelRatio;
|
|
29164
29164
|
const topLeftCanvas = [0, 0];
|
|
29165
|
-
const topRightCanvas = [canvas.width, 0];
|
|
29166
|
-
const bottomRightCanvas = [
|
|
29167
|
-
|
|
29165
|
+
const topRightCanvas = [canvas.width / ratio, 0];
|
|
29166
|
+
const bottomRightCanvas = [
|
|
29167
|
+
canvas.width / ratio,
|
|
29168
|
+
canvas.height / ratio,
|
|
29169
|
+
];
|
|
29170
|
+
const bottomLeftCanvas = [0, canvas.height / ratio];
|
|
29168
29171
|
const topLeftWorld = viewport.canvasToWorld(topLeftCanvas);
|
|
29169
29172
|
const topRightWorld = viewport.canvasToWorld(topRightCanvas);
|
|
29170
29173
|
const bottomRightWorld = viewport.canvasToWorld(bottomRightCanvas);
|
|
@@ -30893,6 +30896,31 @@ class Viewport {
|
|
|
30893
30896
|
this.getProperties = () => ({});
|
|
30894
30897
|
this.setRotation = (_rotation) => {
|
|
30895
30898
|
};
|
|
30899
|
+
this.viewportWidgets = new Map();
|
|
30900
|
+
this.addWidget = (widgetId, widget) => {
|
|
30901
|
+
this.viewportWidgets.set(widgetId, widget);
|
|
30902
|
+
};
|
|
30903
|
+
this.getWidget = (id) => {
|
|
30904
|
+
return this.viewportWidgets.get(id);
|
|
30905
|
+
};
|
|
30906
|
+
this.getWidgets = () => {
|
|
30907
|
+
return Array.from(this.viewportWidgets.values());
|
|
30908
|
+
};
|
|
30909
|
+
this.removeWidgets = () => {
|
|
30910
|
+
const widgets = this.getWidgets();
|
|
30911
|
+
widgets.forEach((widget) => {
|
|
30912
|
+
if (widget.getEnabled()) {
|
|
30913
|
+
widget.setEnabled(false);
|
|
30914
|
+
}
|
|
30915
|
+
if (widget.getActor && widget.getRenderer) {
|
|
30916
|
+
const actor = widget.getActor();
|
|
30917
|
+
const renderer = widget.getRenderer();
|
|
30918
|
+
if (renderer && actor) {
|
|
30919
|
+
renderer.removeActor(actor);
|
|
30920
|
+
}
|
|
30921
|
+
}
|
|
30922
|
+
});
|
|
30923
|
+
};
|
|
30896
30924
|
this.id = props.id;
|
|
30897
30925
|
this.renderingEngineId = props.renderingEngineId;
|
|
30898
30926
|
this.type = props.type;
|
|
@@ -31870,7 +31898,7 @@ class BaseVolumeViewport extends RenderingEngine_Viewport {
|
|
|
31870
31898
|
if (!applicableVolumeActorInfo) {
|
|
31871
31899
|
return;
|
|
31872
31900
|
}
|
|
31873
|
-
const { colormap: latestColormap, VOILUTFunction, interpolationType, invert, slabThickness, rotation, } = this.viewportProperties;
|
|
31901
|
+
const { colormap: latestColormap, VOILUTFunction, interpolationType, invert, slabThickness, rotation, preset, } = this.viewportProperties;
|
|
31874
31902
|
const voiRanges = this.getActors()
|
|
31875
31903
|
.map((actorEntry) => {
|
|
31876
31904
|
const volumeActor = actorEntry.actor;
|
|
@@ -31886,15 +31914,11 @@ class BaseVolumeViewport extends RenderingEngine_Viewport {
|
|
|
31886
31914
|
return { volumeId, voiRange: { lower, upper } };
|
|
31887
31915
|
})
|
|
31888
31916
|
.filter(Boolean);
|
|
31889
|
-
const voiRange =
|
|
31917
|
+
const voiRange = volumeId
|
|
31918
|
+
? voiRanges.find((range) => range.volumeId === volumeId)?.voiRange
|
|
31919
|
+
: voiRanges[0]?.voiRange;
|
|
31890
31920
|
const volumeColormap = this.getColormap(applicableVolumeActorInfo);
|
|
31891
|
-
|
|
31892
|
-
if (volumeId && volumeColormap) {
|
|
31893
|
-
colormap = volumeColormap;
|
|
31894
|
-
}
|
|
31895
|
-
else {
|
|
31896
|
-
colormap = latestColormap;
|
|
31897
|
-
}
|
|
31921
|
+
const colormap = volumeId && volumeColormap ? volumeColormap : latestColormap;
|
|
31898
31922
|
return {
|
|
31899
31923
|
colormap: colormap,
|
|
31900
31924
|
voiRange: voiRange,
|
|
@@ -31903,6 +31927,7 @@ class BaseVolumeViewport extends RenderingEngine_Viewport {
|
|
|
31903
31927
|
invert: invert,
|
|
31904
31928
|
slabThickness: slabThickness,
|
|
31905
31929
|
rotation: rotation,
|
|
31930
|
+
preset,
|
|
31906
31931
|
};
|
|
31907
31932
|
};
|
|
31908
31933
|
this.getColormap = (applicableVolumeActorInfo) => {
|
|
@@ -32113,8 +32138,6 @@ class BaseVolumeViewport extends RenderingEngine_Viewport {
|
|
|
32113
32138
|
return;
|
|
32114
32139
|
}
|
|
32115
32140
|
const { volumeActor } = applicableVolumeActorInfo;
|
|
32116
|
-
const mapper = volumeActor.getMapper();
|
|
32117
|
-
mapper.setSampleDistance(1.0);
|
|
32118
32141
|
const cfun = ColorTransferFunction/* default.newInstance */.Ay.newInstance();
|
|
32119
32142
|
let colormapObj = colormap_getColormap(colormap.name);
|
|
32120
32143
|
const { name } = colormap;
|
|
@@ -32162,6 +32185,9 @@ class BaseVolumeViewport extends RenderingEngine_Viewport {
|
|
|
32162
32185
|
});
|
|
32163
32186
|
}
|
|
32164
32187
|
volumeActor.getProperty().setScalarOpacity(0, ofun);
|
|
32188
|
+
if (!this.viewportProperties.colormap) {
|
|
32189
|
+
this.viewportProperties.colormap = {};
|
|
32190
|
+
}
|
|
32165
32191
|
this.viewportProperties.colormap.opacity = colormap.opacity;
|
|
32166
32192
|
}
|
|
32167
32193
|
setInvert(inverted, volumeId, suppressEvents) {
|
|
@@ -32385,6 +32411,8 @@ class BaseVolumeViewport extends RenderingEngine_Viewport {
|
|
|
32385
32411
|
return;
|
|
32386
32412
|
}
|
|
32387
32413
|
applyPreset(volumeActor, preset);
|
|
32414
|
+
this.viewportProperties.preset = preset;
|
|
32415
|
+
this.render();
|
|
32388
32416
|
if (!suppressEvents) {
|
|
32389
32417
|
triggerEvent(this.element, enums_Events.PRESET_MODIFIED, {
|
|
32390
32418
|
viewportId: this.id,
|
|
@@ -36375,8 +36403,8 @@ class StackViewport extends RenderingEngine_Viewport {
|
|
|
36375
36403
|
viewportId: this.id,
|
|
36376
36404
|
renderingEngineId: this.renderingEngineId,
|
|
36377
36405
|
};
|
|
36378
|
-
triggerEvent(this.element, enums_Events.STACK_NEW_IMAGE, eventDetail);
|
|
36379
36406
|
this._updateActorToDisplayImageId(image);
|
|
36407
|
+
triggerEvent(this.element, enums_Events.STACK_NEW_IMAGE, eventDetail);
|
|
36380
36408
|
this.render();
|
|
36381
36409
|
this.currentImageIdIndex = imageIdIndex;
|
|
36382
36410
|
}
|
|
@@ -36504,6 +36532,7 @@ class StackViewport extends RenderingEngine_Viewport {
|
|
|
36504
36532
|
activeCamera.setFreezeFocalPoint(true);
|
|
36505
36533
|
this._restoreCameraProps(cameraProps, previousCameraProps, panCache);
|
|
36506
36534
|
this._setPropertiesFromCache();
|
|
36535
|
+
this.stackActorReInitialized = false;
|
|
36507
36536
|
return;
|
|
36508
36537
|
}
|
|
36509
36538
|
const { origin, direction, dimensions, spacing, numComps, imagePixelModule, } = this.getImageDataMetadata(image);
|
|
@@ -36541,6 +36570,7 @@ class StackViewport extends RenderingEngine_Viewport {
|
|
|
36541
36570
|
this.setInvertColor(this.invert || this.initialInvert);
|
|
36542
36571
|
this.cameraFocalPointOnRender = this.getCamera().focalPoint;
|
|
36543
36572
|
this.stackInvalidated = false;
|
|
36573
|
+
this.stackActorReInitialized = true;
|
|
36544
36574
|
if (this._publishCalibratedEvent) {
|
|
36545
36575
|
this.triggerCalibrationEvent();
|
|
36546
36576
|
}
|
|
@@ -38393,6 +38423,7 @@ class RenderingEngine {
|
|
|
38393
38423
|
viewportId,
|
|
38394
38424
|
renderingEngineId,
|
|
38395
38425
|
};
|
|
38426
|
+
viewport.removeWidgets();
|
|
38396
38427
|
triggerEvent(esm_eventTarget, enums_Events.ELEMENT_DISABLED, eventDetail);
|
|
38397
38428
|
element.removeAttribute('data-viewport-uid');
|
|
38398
38429
|
element.removeAttribute('data-rendering-engine-uid');
|
|
@@ -52533,6 +52564,7 @@ class AnnotationTool extends _AnnotationDisplayTool__WEBPACK_IMPORTED_MODULE_2__
|
|
|
52533
52564
|
const enabledElement = (0,_cornerstonejs_core__WEBPACK_IMPORTED_MODULE_0__.getEnabledElement)(element);
|
|
52534
52565
|
const { viewport } = enabledElement;
|
|
52535
52566
|
const { data } = annotation;
|
|
52567
|
+
const { isCanvasAnnotation } = data;
|
|
52536
52568
|
const { points, textBox } = data.handles;
|
|
52537
52569
|
if (textBox) {
|
|
52538
52570
|
const { worldBoundingBox } = textBox;
|
|
@@ -52554,7 +52586,9 @@ class AnnotationTool extends _AnnotationDisplayTool__WEBPACK_IMPORTED_MODULE_2__
|
|
|
52554
52586
|
}
|
|
52555
52587
|
for (let i = 0; i < points?.length; i++) {
|
|
52556
52588
|
const point = points[i];
|
|
52557
|
-
const annotationCanvasCoordinate =
|
|
52589
|
+
const annotationCanvasCoordinate = isCanvasAnnotation
|
|
52590
|
+
? point.slice(0, 2)
|
|
52591
|
+
: viewport.worldToCanvas(point);
|
|
52558
52592
|
const near = gl_matrix__WEBPACK_IMPORTED_MODULE_1__/* .vec2.distance */ .Zc.distance(canvasCoords, annotationCanvasCoordinate) < proximity;
|
|
52559
52593
|
if (near === true) {
|
|
52560
52594
|
data.handles.activeHandleIndex = i;
|
|
@@ -53009,6 +53043,11 @@ function _setLabelmapColorAndOpacity(viewportId, actorEntry, cfun, ofun, colorLU
|
|
|
53009
53043
|
const { activeSegmentIndex } = _stateManagement_segmentation_segmentationState__WEBPACK_IMPORTED_MODULE_4__.getSegmentation(segmentationRepresentation.segmentationId);
|
|
53010
53044
|
const outlineWidths = new Array(numColors - 1);
|
|
53011
53045
|
for (let i = 1; i < numColors; i++) {
|
|
53046
|
+
const isHidden = segmentsHidden.has(i);
|
|
53047
|
+
if (isHidden) {
|
|
53048
|
+
outlineWidths[i - 1] = 0;
|
|
53049
|
+
continue;
|
|
53050
|
+
}
|
|
53012
53051
|
outlineWidths[i - 1] =
|
|
53013
53052
|
i === activeSegmentIndex
|
|
53014
53053
|
? outlineWidth + toolGroupLabelmapConfig.activeSegmentOutlineWidthDelta
|
|
@@ -55614,8 +55653,8 @@ class AdvancedMagnifyTool extends base/* AnnotationTool */.EC {
|
|
|
55614
55653
|
shadow: true,
|
|
55615
55654
|
magnifyingGlass: {
|
|
55616
55655
|
radius: 125,
|
|
55617
|
-
zoomFactor:
|
|
55618
|
-
zoomFactorList: [2.5, 3, 3.5, 4, 4.5, 5],
|
|
55656
|
+
zoomFactor: 3,
|
|
55657
|
+
zoomFactorList: [1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5],
|
|
55619
55658
|
autoPan: {
|
|
55620
55659
|
enabled: true,
|
|
55621
55660
|
padding: 10,
|
|
@@ -55644,7 +55683,7 @@ class AdvancedMagnifyTool extends base/* AnnotationTool */.EC {
|
|
|
55644
55683
|
const canvasPos = currentPoints.canvas;
|
|
55645
55684
|
const { magnifyingGlass: config } = this.configuration;
|
|
55646
55685
|
const { radius, zoomFactor, autoPan } = config;
|
|
55647
|
-
const
|
|
55686
|
+
const canvasHandlePoints = this._getCanvasHandlePoints(canvasPos, radius);
|
|
55648
55687
|
const camera = viewport.getCamera();
|
|
55649
55688
|
const { viewPlaneNormal, viewUp } = camera;
|
|
55650
55689
|
const referencedImageId = this.getReferencedImageId(viewport, worldPos, viewPlaneNormal, viewUp);
|
|
@@ -55666,8 +55705,9 @@ class AdvancedMagnifyTool extends base/* AnnotationTool */.EC {
|
|
|
55666
55705
|
sourceViewportId: viewport.id,
|
|
55667
55706
|
magnifyViewportId,
|
|
55668
55707
|
zoomFactor,
|
|
55708
|
+
isCanvasAnnotation: true,
|
|
55669
55709
|
handles: {
|
|
55670
|
-
points:
|
|
55710
|
+
points: canvasHandlePoints,
|
|
55671
55711
|
activeHandleIndex: null,
|
|
55672
55712
|
},
|
|
55673
55713
|
},
|
|
@@ -55683,11 +55723,12 @@ class AdvancedMagnifyTool extends base/* AnnotationTool */.EC {
|
|
|
55683
55723
|
padding: autoPan.padding,
|
|
55684
55724
|
callback: (data) => {
|
|
55685
55725
|
const annotationPoints = annotation.data.handles.points;
|
|
55686
|
-
const {
|
|
55726
|
+
const { canvas: canvasDelta } = data.delta;
|
|
55687
55727
|
for (let i = 0, len = annotationPoints.length; i < len; i++) {
|
|
55688
|
-
annotationPoints[i]
|
|
55689
|
-
|
|
55690
|
-
|
|
55728
|
+
const point = annotationPoints[i];
|
|
55729
|
+
point[0] += canvasDelta[0];
|
|
55730
|
+
point[1] += canvasDelta[1];
|
|
55731
|
+
annotation.invalidated = true;
|
|
55691
55732
|
}
|
|
55692
55733
|
},
|
|
55693
55734
|
},
|
|
@@ -55708,11 +55749,9 @@ class AdvancedMagnifyTool extends base/* AnnotationTool */.EC {
|
|
|
55708
55749
|
});
|
|
55709
55750
|
};
|
|
55710
55751
|
this.isPointNearTool = (element, annotation, canvasCoords, proximity) => {
|
|
55711
|
-
const enabledElement = (0,esm.getEnabledElement)(element);
|
|
55712
|
-
const { viewport } = enabledElement;
|
|
55713
55752
|
const { data } = annotation;
|
|
55714
55753
|
const { points } = data.handles;
|
|
55715
|
-
const canvasCoordinates = points
|
|
55754
|
+
const canvasCoordinates = points;
|
|
55716
55755
|
const canvasTop = canvasCoordinates[0];
|
|
55717
55756
|
const canvasBottom = canvasCoordinates[2];
|
|
55718
55757
|
const canvasLeft = canvasCoordinates[3];
|
|
@@ -55722,7 +55761,7 @@ class AdvancedMagnifyTool extends base/* AnnotationTool */.EC {
|
|
|
55722
55761
|
canvasTop[1] + radius,
|
|
55723
55762
|
];
|
|
55724
55763
|
const radiusPoint = (0,circle/* getCanvasCircleRadius */.r)([center, canvasCoords]);
|
|
55725
|
-
if (Math.abs(radiusPoint - radius) < proximity *
|
|
55764
|
+
if (Math.abs(radiusPoint - radius) < proximity * 2) {
|
|
55726
55765
|
return true;
|
|
55727
55766
|
}
|
|
55728
55767
|
return false;
|
|
@@ -55784,15 +55823,14 @@ class AdvancedMagnifyTool extends base/* AnnotationTool */.EC {
|
|
|
55784
55823
|
this.isDrawing = true;
|
|
55785
55824
|
const eventDetail = evt.detail;
|
|
55786
55825
|
const { element, deltaPoints } = eventDetail;
|
|
55787
|
-
const
|
|
55826
|
+
const canvasDelta = deltaPoints?.canvas ?? [0, 0, 0];
|
|
55788
55827
|
const enabledElement = (0,esm.getEnabledElement)(element);
|
|
55789
55828
|
const { renderingEngine } = enabledElement;
|
|
55790
55829
|
const { annotation, viewportIdsToRender } = this.editData;
|
|
55791
55830
|
const { points } = annotation.data.handles;
|
|
55792
55831
|
points.forEach((point) => {
|
|
55793
|
-
point[0] +=
|
|
55794
|
-
point[1] +=
|
|
55795
|
-
point[2] += worldPosDelta[2];
|
|
55832
|
+
point[0] += canvasDelta[0];
|
|
55833
|
+
point[1] += canvasDelta[1];
|
|
55796
55834
|
});
|
|
55797
55835
|
annotation.invalidated = true;
|
|
55798
55836
|
this.editData.hasMoved = true;
|
|
@@ -55806,12 +55844,11 @@ class AdvancedMagnifyTool extends base/* AnnotationTool */.EC {
|
|
|
55806
55844
|
const { data } = annotation;
|
|
55807
55845
|
if (handleIndex === undefined) {
|
|
55808
55846
|
const { deltaPoints } = eventDetail;
|
|
55809
|
-
const
|
|
55847
|
+
const canvasDelta = deltaPoints.canvas;
|
|
55810
55848
|
const points = data.handles.points;
|
|
55811
55849
|
points.forEach((point) => {
|
|
55812
|
-
point[0] +=
|
|
55813
|
-
point[1] +=
|
|
55814
|
-
point[2] += worldPosDelta[2];
|
|
55850
|
+
point[0] += canvasDelta[0];
|
|
55851
|
+
point[1] += canvasDelta[1];
|
|
55815
55852
|
});
|
|
55816
55853
|
annotation.invalidated = true;
|
|
55817
55854
|
}
|
|
@@ -55825,14 +55862,10 @@ class AdvancedMagnifyTool extends base/* AnnotationTool */.EC {
|
|
|
55825
55862
|
};
|
|
55826
55863
|
this._dragHandle = (evt) => {
|
|
55827
55864
|
const eventDetail = evt.detail;
|
|
55828
|
-
const { element } = eventDetail;
|
|
55829
|
-
const enabledElement = (0,esm.getEnabledElement)(element);
|
|
55830
|
-
const { viewport } = enabledElement;
|
|
55831
|
-
const { worldToCanvas } = viewport;
|
|
55832
55865
|
const { annotation } = this.editData;
|
|
55833
55866
|
const { data } = annotation;
|
|
55834
55867
|
const { points } = data.handles;
|
|
55835
|
-
const canvasCoordinates = points
|
|
55868
|
+
const canvasCoordinates = points;
|
|
55836
55869
|
const canvasTop = canvasCoordinates[0];
|
|
55837
55870
|
const canvasBottom = canvasCoordinates[2];
|
|
55838
55871
|
const canvasLeft = canvasCoordinates[3];
|
|
@@ -55847,11 +55880,11 @@ class AdvancedMagnifyTool extends base/* AnnotationTool */.EC {
|
|
|
55847
55880
|
canvasCenter,
|
|
55848
55881
|
currentCanvasPoints,
|
|
55849
55882
|
]);
|
|
55850
|
-
const
|
|
55851
|
-
points[0] =
|
|
55852
|
-
points[1] =
|
|
55853
|
-
points[2] =
|
|
55854
|
-
points[3] =
|
|
55883
|
+
const newCanvasHandlePoints = this._getCanvasHandlePoints(canvasCenter, newRadius);
|
|
55884
|
+
points[0] = newCanvasHandlePoints[0];
|
|
55885
|
+
points[1] = newCanvasHandlePoints[1];
|
|
55886
|
+
points[2] = newCanvasHandlePoints[2];
|
|
55887
|
+
points[3] = newCanvasHandlePoints[3];
|
|
55855
55888
|
};
|
|
55856
55889
|
this.cancel = (element) => {
|
|
55857
55890
|
if (!this.isDrawing) {
|
|
@@ -55899,10 +55932,10 @@ class AdvancedMagnifyTool extends base/* AnnotationTool */.EC {
|
|
|
55899
55932
|
if (!annotations?.length) {
|
|
55900
55933
|
return renderStatus;
|
|
55901
55934
|
}
|
|
55902
|
-
annotations = this.filterInteractableAnnotationsForElement(element, annotations);
|
|
55903
55935
|
annotations = annotations?.filter((annotation) => annotation.data.sourceViewportId ===
|
|
55904
55936
|
viewport.id);
|
|
55905
|
-
|
|
55937
|
+
const filteredAnnotations = this.filterInteractableAnnotationsForElement(element, annotations);
|
|
55938
|
+
if (!filteredAnnotations?.length) {
|
|
55906
55939
|
return renderStatus;
|
|
55907
55940
|
}
|
|
55908
55941
|
const styleSpecifier = {
|
|
@@ -55910,8 +55943,8 @@ class AdvancedMagnifyTool extends base/* AnnotationTool */.EC {
|
|
|
55910
55943
|
toolName: this.getToolName(),
|
|
55911
55944
|
viewportId: enabledElement.viewport.id,
|
|
55912
55945
|
};
|
|
55913
|
-
for (let i = 0; i <
|
|
55914
|
-
const annotation =
|
|
55946
|
+
for (let i = 0; i < filteredAnnotations.length; i++) {
|
|
55947
|
+
const annotation = filteredAnnotations[i];
|
|
55915
55948
|
const { annotationUID, data } = annotation;
|
|
55916
55949
|
const { magnifyViewportId, zoomFactor, handles } = data;
|
|
55917
55950
|
const { points, activeHandleIndex } = handles;
|
|
@@ -55919,7 +55952,7 @@ class AdvancedMagnifyTool extends base/* AnnotationTool */.EC {
|
|
|
55919
55952
|
const lineWidth = this.getStyle('lineWidth', styleSpecifier, annotation);
|
|
55920
55953
|
const lineDash = this.getStyle('lineDash', styleSpecifier, annotation);
|
|
55921
55954
|
const color = this.getStyle('color', styleSpecifier, annotation);
|
|
55922
|
-
const canvasCoordinates = points
|
|
55955
|
+
const canvasCoordinates = points;
|
|
55923
55956
|
const canvasTop = canvasCoordinates[0];
|
|
55924
55957
|
const canvasBottom = canvasCoordinates[2];
|
|
55925
55958
|
const canvasLeft = canvasCoordinates[3];
|
|
@@ -55962,15 +55995,13 @@ class AdvancedMagnifyTool extends base/* AnnotationTool */.EC {
|
|
|
55962
55995
|
}
|
|
55963
55996
|
return renderStatus;
|
|
55964
55997
|
};
|
|
55965
|
-
this.
|
|
55966
|
-
|
|
55967
|
-
[canvasCenterPos[0], canvasCenterPos[1] - canvasRadius],
|
|
55968
|
-
[canvasCenterPos[0] + canvasRadius, canvasCenterPos[1]],
|
|
55969
|
-
[canvasCenterPos[0], canvasCenterPos[1] + canvasRadius],
|
|
55970
|
-
[canvasCenterPos[0] - canvasRadius, canvasCenterPos[1]],
|
|
55998
|
+
this._getCanvasHandlePoints = (canvasCenterPos, canvasRadius) => {
|
|
55999
|
+
return [
|
|
56000
|
+
[canvasCenterPos[0], canvasCenterPos[1] - canvasRadius, 0],
|
|
56001
|
+
[canvasCenterPos[0] + canvasRadius, canvasCenterPos[1], 0],
|
|
56002
|
+
[canvasCenterPos[0], canvasCenterPos[1] + canvasRadius, 0],
|
|
56003
|
+
[canvasCenterPos[0] - canvasRadius, canvasCenterPos[1], 0],
|
|
55971
56004
|
];
|
|
55972
|
-
const worldHandlesPoints = canvasHandlesPoints.map((p) => viewport.canvasToWorld(p));
|
|
55973
|
-
return worldHandlesPoints;
|
|
55974
56005
|
};
|
|
55975
56006
|
this.magnifyViewportManager = AdvancedMagnifyViewportManager/* default */.A.getInstance();
|
|
55976
56007
|
}
|
|
@@ -65607,7 +65638,11 @@ class OrientationMarkerTool extends base/* BaseTool */.oS {
|
|
|
65607
65638
|
}
|
|
65608
65639
|
let viewports = renderingEngine.getViewports();
|
|
65609
65640
|
viewports = (0,viewportFilters.filterViewportsWithToolEnabled)(viewports, this.getToolName());
|
|
65610
|
-
viewports.forEach((viewport) =>
|
|
65641
|
+
viewports.forEach((viewport) => {
|
|
65642
|
+
if (!viewport.getWidget(this.getToolName())) {
|
|
65643
|
+
this.addAxisActorInViewport(viewport);
|
|
65644
|
+
}
|
|
65645
|
+
});
|
|
65611
65646
|
}
|
|
65612
65647
|
async addAxisActorInViewport(viewport) {
|
|
65613
65648
|
const viewportId = viewport.id;
|
|
@@ -65648,6 +65683,7 @@ class OrientationMarkerTool extends base/* BaseTool */.oS {
|
|
|
65648
65683
|
orientationWidget,
|
|
65649
65684
|
actor,
|
|
65650
65685
|
};
|
|
65686
|
+
viewport.addWidget(this.getToolName(), orientationWidget);
|
|
65651
65687
|
renderWindow.render();
|
|
65652
65688
|
viewport.getRenderingEngine().render();
|
|
65653
65689
|
this.configuration_invalidated = false;
|
|
@@ -65930,7 +65966,6 @@ class BrushTool extends _base__WEBPACK_IMPORTED_MODULE_2__/* .BaseTool */ .oS {
|
|
|
65930
65966
|
strategySpecificConfiguration: {
|
|
65931
65967
|
THRESHOLD: {
|
|
65932
65968
|
threshold: [-150, -70],
|
|
65933
|
-
dynamicRadius: 0,
|
|
65934
65969
|
},
|
|
65935
65970
|
},
|
|
65936
65971
|
defaultStrategy: 'FILL_INSIDE_CIRCLE',
|
|
@@ -66111,6 +66146,18 @@ class BrushTool extends _base__WEBPACK_IMPORTED_MODULE_2__/* .BaseTool */ .oS {
|
|
|
66111
66146
|
if ((0,_strategies_utils_stackVolumeCheck__WEBPACK_IMPORTED_MODULE_12__/* .isVolumeSegmentation */ .r)(labelmapData, viewport)) {
|
|
66112
66147
|
const { volumeId } = representationData[type];
|
|
66113
66148
|
const actors = viewport.getActors();
|
|
66149
|
+
const isStackViewport = viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_0__.StackViewport;
|
|
66150
|
+
if (isStackViewport) {
|
|
66151
|
+
const event = new CustomEvent(_cornerstonejs_core__WEBPACK_IMPORTED_MODULE_0__.Enums.Events.ERROR_EVENT, {
|
|
66152
|
+
detail: {
|
|
66153
|
+
type: 'Segmentation',
|
|
66154
|
+
message: 'Cannot perform brush operation on the selected viewport',
|
|
66155
|
+
},
|
|
66156
|
+
cancelable: true,
|
|
66157
|
+
});
|
|
66158
|
+
_cornerstonejs_core__WEBPACK_IMPORTED_MODULE_0__.eventTarget.dispatchEvent(event);
|
|
66159
|
+
return null;
|
|
66160
|
+
}
|
|
66114
66161
|
const volumes = actors.map((actorEntry) => _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_0__.cache.getVolume(actorEntry.referenceId));
|
|
66115
66162
|
const segmentationVolume = _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_0__.cache.getVolume(volumeId);
|
|
66116
66163
|
const referencedVolumeIdToThreshold = volumes.find((volume) => _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_0__.utilities.isEqual(volume.dimensions, segmentationVolume.dimensions))?.volumeId || volumes[0]?.volumeId;
|
|
@@ -68118,10 +68165,10 @@ function playClip(element, playClipOptions) {
|
|
|
68118
68165
|
};
|
|
68119
68166
|
triggerEvent(element, CINE_EVENTS.CLIP_STARTED, eventDetail);
|
|
68120
68167
|
}
|
|
68121
|
-
function stopClip(element,
|
|
68168
|
+
function stopClip(element, options = {}) {
|
|
68122
68169
|
_stopClip(element, {
|
|
68123
68170
|
stopDynamicCine: true,
|
|
68124
|
-
|
|
68171
|
+
...options,
|
|
68125
68172
|
});
|
|
68126
68173
|
}
|
|
68127
68174
|
function _stopClip(element, options = { stopDynamicCine: true, viewportId: undefined }) {
|