"use strict";

function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

var _react = _interopRequireDefault(require("react"));

var _propTypes = _interopRequireDefault(require("prop-types"));

require("./Vol3dViewer.css");

var THREE = _interopRequireWildcard(require("three"));

var _threeOrbitUnlimitedControls = _interopRequireDefault(require("@janelia/three-orbit-unlimited-controls"));

var _Shaders = require("./Shaders");

var _Utils = require("./Utils");

function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }

function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }

function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }

function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }

function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }

function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }

function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }

function Vol3dViewer(props) {
  var volumeDataUint8 = props.volumeDataUint8,
      volumeSize = props.volumeSize,
      voxelSize = props.voxelSize,
      useVolumeMirrorX = props.useVolumeMirrorX,
      alphaScale = props.alphaScale,
      dtScale = props.dtScale,
      transferFunctionTex = props.transferFunctionTex,
      finalGamma = props.finalGamma,
      interactionSpeedup = props.interactionSpeedup,
      cameraPosition = props.cameraPosition,
      cameraTarget = props.cameraTarget,
      cameraUp = props.cameraUp,
      cameraFovDegrees = props.cameraFovDegrees,
      orbitZoomSpeed = props.orbitZoomSpeed,
      useLighting = props.useLighting,
      useSurface = props.useSurface,
      surfaceMesh = props.surfaceMesh,
      surfaceColor = props.surfaceColor,
      onCameraChange = props.onCameraChange,
      onWebGLRender = props.onWebGLRender; // For mounting the Three.js renderer image in the appropriate place in the DOM.

  var mountRef = _react.default.useRef(null); // Some Three.js values that need to be referenced after initialization.
  // According to https://reactjs.org/docs/hooks-reference.html#useref, 
  // `useRef` "is handy for keeping any mutable value around similar to how you’d use
  // instance fields in classes."  Note that trying to store these particular values
  // with `useState` seems to cause repeated updates and a crash.


  var rendererRef = _react.default.useRef(null);

  var cameraRef = _react.default.useRef(null);

  var sceneRef = _react.default.useRef(null);

  var boxRef = _react.default.useRef(null);

  var boxMaterialRef = _react.default.useRef(null);

  var trackballRef = _react.default.useRef(null);

  var surfaceRef = _react.default.useRef(null);

  var surfaceTargetRef = _react.default.useRef(null);

  var onCameraChangeRef = _react.default.useRef(null);

  var prevHeightRef = _react.default.useRef(null);

  var cameraNear = 0.01;
  var cameraFar = 10.0; // Different props affect different parts of the Three.js state, and a change to only
  // one prop should not causes all the Three.js state to be reinitialized.  It is not clear
  // that the Three.js state could be split between multiple React components, each having
  // only the appropriate subset of the props.  So this component makes significant use of
  // the `React.useEffect` hook, with a different hook for each part of the Three.js state
  // that needs to be initialized based on particular props.  Those particular props, and
  // any other data dependent on them, are listed in the array that is the second argument
  // to `React.useEffect`, and the code that is first argument is executed only the when
  // those props change.

  _react.default.useEffect(function () {
    var initRenderer = function initRenderer() {
      console.log('initRenderer'); // Three.js now uses WebGL 2 by default, so no special canvas context is needed.

      var renderer = new THREE.WebGLRenderer({
        antialias: true
      });
      renderer.setClearColor("#000000"); // For a shader using `gl_FragCoord`, as in this code (Shaders.js), the following
      // use of `setPixelRatio` is not recommended in this guide:
      // https://threejs.org/manual/#en/responsive
      // On the other hand, the Three.js authors say the following use is correct:
      // https://github.com/mrdoob/three.js/issues/12770
      // Eliminates some artifacts on MacBook Pros with Retina displays.

      renderer.setPixelRatio(window.devicePixelRatio); // Must be called after setPixelRatio().

      var width = mountRef.current.clientWidth;
      var height = mountRef.current.clientHeight;
      renderer.setSize(width, height); // The `clientHeight` does not seem to change when resizing to a shorter height.
      // So keep track of the `innerHeight`, which does change, and use it for a correction.

      prevHeightRef.current = window.innerHeight;
      mountRef.current.appendChild(renderer.domElement);
      return renderer;
    };

    var initScene = function initScene() {
      console.log('initScene');
      var scene = new THREE.Scene(); // A box in which the 3D volume texture will be rendered.  The box will be
      // centered at the origin, with X in [-0.5, 0.5] so the width is 1, and
      // Y (height) and Z (depth) scaled to match.

      var _getBoxSize = (0, _Utils.getBoxSize)(volumeSize, voxelSize),
          _getBoxSize2 = _slicedToArray(_getBoxSize, 3),
          boxWidth = _getBoxSize2[0],
          boxHeight = _getBoxSize2[1],
          boxDepth = _getBoxSize2[2];

      var boxSize = new THREE.Vector3(boxWidth, boxHeight, boxDepth);
      console.log("Voxel size ".concat(voxelSize[0], ", ").concat(voxelSize[1], ", ").concat(voxelSize[2]));
      console.log("Box size ".concat(boxWidth, ", ").concat(boxHeight, ", ").concat(boxDepth));
      var boxGeometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
      var box = new THREE.Mesh(boxGeometry);
      scene.add(box); // Lights, to be used both during rendering the volume, and rendering the optional surface.

      var directionalLightPos0 = new THREE.Vector3(-0.2, 1.0, 0.0).normalize();
      var directionalLightPos1 = new THREE.Vector3(-1.0, -1.0, 1.0).normalize();
      var directionalLightPos2 = new THREE.Vector3(1.0, -1.0, -1.0).normalize();
      var directionalLightColor0 = new THREE.Color(0.9, 0.9, 0.9);
      var directionalLightColor1 = new THREE.Color(0.4, 0.5, 0.6);
      var directionalLightColor2 = new THREE.Color(0.7, 0.8, 1.0);
      var directionalLight0 = new THREE.DirectionalLight(directionalLightColor0.getHex(), 1);
      directionalLight0.position.copy(directionalLightPos0);
      var directionalLight1 = new THREE.DirectionalLight(directionalLightColor1.getHex(), 1);
      directionalLight1.position.copy(directionalLightPos1);
      var directionalLight2 = new THREE.DirectionalLight(directionalLightColor2.getHex(), 1);
      directionalLight2.position.copy(directionalLightPos2);
      scene.add(directionalLight0);
      scene.add(directionalLight1);
      scene.add(directionalLight2);
      return [scene, box, boxSize, directionalLight0, directionalLight1, directionalLight2];
    };

    var initMaterial = function initMaterial(renderer, box, boxSize, directionalLight0, directionalLight1, directionalLight2) {
      var volumeTexture = new THREE.DataTexture3D(volumeDataUint8, volumeSize[0], volumeSize[1], volumeSize[2]);
      volumeTexture.format = THREE.RedFormat;
      volumeTexture.type = THREE.UnsignedByteType; // Disabling mimpaps saves memory.

      volumeTexture.generateMipmaps = false; // Linear filtering disables LODs, which do not help with volume rendering.

      volumeTexture.minFilter = THREE.LinearFilter;
      volumeTexture.magFilter = THREE.LinearFilter;
      volumeTexture.needsUpdate = true;
      var lightColor0 = directionalLight0.color;
      var lightColor1 = directionalLight1.color;
      var lightColor2 = directionalLight2.color;
      var lightColorV0 = new THREE.Vector3(lightColor0.r, lightColor0.g, lightColor0.b);
      var lightColorV1 = new THREE.Vector3(lightColor1.r, lightColor1.g, lightColor1.b);
      var lightColorV2 = new THREE.Vector3(lightColor2.r, lightColor2.g, lightColor1.b);
      var boxMaterial = new THREE.ShaderMaterial({
        vertexShader: _Shaders.vertexShaderVolume,
        fragmentShader: _Shaders.fragmentShaderVolume,
        side: THREE.BackSide,
        uniforms: {
          boxSize: new THREE.Uniform(boxSize),
          volumeTex: new THREE.Uniform(volumeTexture),
          light0: new THREE.Uniform(directionalLight0.position),
          light1: new THREE.Uniform(directionalLight1.position),
          light2: new THREE.Uniform(directionalLight2.position),
          lightColor0: new THREE.Uniform(lightColorV0),
          lightColor1: new THREE.Uniform(lightColorV1),
          lightColor2: new THREE.Uniform(lightColorV2),
          near: new THREE.Uniform(cameraNear),
          far: new THREE.Uniform(cameraFar),
          // The following are set separately, since they are based on `props` values that can
          // change often, and should not trigger complete re-initialization.
          transferTex: new THREE.Uniform(null),
          alphaScale: new THREE.Uniform(0),
          dtScale: new THREE.Uniform(0),
          finalGamma: new THREE.Uniform(0),
          useLighting: new THREE.Uniform(true),
          useSurface: new THREE.Uniform(false),
          surfaceColorTex: new THREE.Uniform(null),
          surfaceDepthTex: new THREE.Uniform(null),
          useVolumeMirrorX: new THREE.Uniform(false)
        }
      });
      /* eslint no-param-reassign: ["error", { "props": false }] */

      box.material = boxMaterial;
      return [boxMaterial];
    };

    var renderer = initRenderer();

    var _initScene = initScene(),
        _initScene2 = _slicedToArray(_initScene, 6),
        scene = _initScene2[0],
        box = _initScene2[1],
        boxSize = _initScene2[2],
        light0 = _initScene2[3],
        light1 = _initScene2[4],
        light2 = _initScene2[5];

    var _initMaterial = initMaterial(renderer, box, boxSize, light0, light1, light2),
        _initMaterial2 = _slicedToArray(_initMaterial, 1),
        boxMaterial = _initMaterial2[0];

    rendererRef.current = renderer;
    sceneRef.current = scene;
    boxRef.current = box;
    boxMaterialRef.current = boxMaterial; // This "clean up" function will be called when the component is unmounted.  The copy of 
    // `mountRef.current` eliminates the following warning from React: "The ref value 'mountRef.current'
    // will likely have changed by the time this effect cleanup function runs. If this ref points to a
    // node rendered by React, copy 'mountRef.current' to a variable inside the effect, and use that
    // variable in the cleanup function."

    var mnt = mountRef.current;
    return function () {
      return mnt.removeChild(renderer.domElement);
    };
  }, [volumeDataUint8, volumeSize, voxelSize]);

  _react.default.useEffect(function () {
    if (rendererRef.current) {
      console.log('initCamera');
      var renderer = rendererRef.current;
      var size = new THREE.Vector2();
      renderer.getSize(size);
      var camera = new THREE.PerspectiveCamera(cameraFovDegrees, size.x / size.y, cameraNear, cameraFar);
      camera.position.set(cameraPosition[0], cameraPosition[1], cameraPosition[2]);
      camera.up.set(cameraUp[0], cameraUp[1], cameraUp[2]);
      var trackball = new _threeOrbitUnlimitedControls.default(camera, renderer.domElement);
      trackball.target.set(cameraTarget[0], cameraTarget[1], cameraTarget[2]);
      trackball.zoomSpeed = orbitZoomSpeed; // Match the modifier keys used by VVD_Viewer, as described in the FluoRender user manual:
      // http://www.sci.utah.edu/releases/fluorender_v2.20/FluoRender2.20_Manual.pdf
      // Appendix "C. Keyboard Shortcuts"

      trackball.usePanModAlt = true;
      trackball.usePanModCtrl = true;
      trackball.usePanModMeta = true;
      cameraRef.current = camera;
      trackballRef.current = trackball;
    }
  }, [rendererRef, cameraPosition, cameraUp, cameraTarget, cameraFovDegrees, orbitZoomSpeed]); // This rendering function is "memoized" so it can be used in `useEffect` blocks.


  var renderScene = _react.default.useCallback(function () {
    var surfaceVisible = surfaceRef.current && surfaceRef.current.visible;

    if (surfaceVisible) {
      boxRef.current.visible = false;
      var size = new THREE.Vector2();
      rendererRef.current.getDrawingBufferSize(size);

      if (!surfaceTargetRef.current || surfaceTargetRef.current.width !== size.x || surfaceTargetRef.current.height !== size.y) {
        surfaceTargetRef.current = new THREE.WebGLRenderTarget(size.x, size.y);
        surfaceTargetRef.current.texture.format = THREE.RGBFormat;
        surfaceTargetRef.current.texture.minFilter = THREE.NearestFilter;
        surfaceTargetRef.current.texture.magFilter = THREE.NearestFilter;
        surfaceTargetRef.current.texture.generateMipmaps = false;
        surfaceTargetRef.current.depthBuffer = true;
        surfaceTargetRef.current.depthTexture = new THREE.DepthTexture(size.x, size.y);
        surfaceTargetRef.current.depthTexture.format = THREE.DepthFormat;
        surfaceTargetRef.current.depthTexture.type = THREE.UnsignedShortType;
        surfaceTargetRef.current.stencilBuffer = false;
        boxMaterialRef.current.uniforms.surfaceColorTex.value = surfaceTargetRef.current.texture;
        boxMaterialRef.current.uniforms.surfaceDepthTex.value = surfaceTargetRef.current.depthTexture;
      }

      rendererRef.current.setRenderTarget(surfaceTargetRef.current);
      rendererRef.current.render(sceneRef.current, cameraRef.current);
      rendererRef.current.setRenderTarget(null);
      surfaceRef.current.visible = false;
      boxRef.current.visible = true;
    }

    rendererRef.current.render(sceneRef.current, cameraRef.current);

    if (surfaceVisible) {
      surfaceRef.current.visible = true;
    }

    if (onWebGLRender) {
      onWebGLRender();
    }
  }, [onWebGLRender]);

  _react.default.useEffect(function () {
    console.log('update OrbitUnlimitedControls');
    trackballRef.current.addEventListener("change", renderScene); // This `useEffect` should run only once, but if it ever ran again, this "clean up"
    // function would ensure that the current `renderScene` is no longer called.

    return function () {
      return trackballRef.current.removeEventListener("change", renderScene);
    };
  }, [renderScene]);

  _react.default.useEffect(function () {
    console.log('update OrbitUnlimitedControls 2');

    if (onCameraChange) {
      if (onCameraChangeRef.current) {
        trackballRef.current.removeEventListener("change", onCameraChangeRef.current);
      }

      onCameraChangeRef.current = onCameraChange;
      trackballRef.current.addEventListener("change", onCameraChangeRef.current);
    } // This `useEffect` should run only once, but if it ever ran again, this "clean up"
    // function would ensure that the current `onCameraChange` is no longer called.


    return function () {
      return trackballRef.current.removeEventListener("change", onCameraChangeRef.current);
    };
  }, [onCameraChange]);

  _react.default.useEffect(function () {
    console.log('update box material');
    boxMaterialRef.current.uniforms.transferTex.value = transferFunctionTex;
    boxMaterialRef.current.uniforms.alphaScale.value = alphaScale;
    boxMaterialRef.current.uniforms.dtScale.value = dtScale;
    boxMaterialRef.current.uniforms.finalGamma.value = finalGamma;
    boxMaterialRef.current.uniforms.useLighting.value = useLighting;
    boxMaterialRef.current.uniforms.useSurface.value = useSurface;
    boxMaterialRef.current.uniforms.useVolumeMirrorX.value = useVolumeMirrorX; // This `useEffect` follows the first React rendering, so it is necessary to
    // explicitly force a Three.js rendering to make the volme visible before any
    // interactive camera motion.

    renderScene();
  }, [alphaScale, dtScale, finalGamma, renderScene, transferFunctionTex, useLighting, useSurface, useVolumeMirrorX]);

  _react.default.useEffect(function () {
    var initSurface = function initSurface() {
      console.log('initSurface');

      if (surfaceRef.current) {
        sceneRef.current.remove(surfaceRef.current);
      }

      if (surfaceMesh) {
        sceneRef.current.add(surfaceMesh);

        if (surfaceRef.current) {
          surfaceMesh.visible = surfaceRef.current.visible;
        }
      }

      return surfaceMesh;
    };

    surfaceRef.current = initSurface();
    renderScene();
  }, [renderScene, sceneRef, surfaceRef, surfaceMesh]); // Surface color must be changed with `useEffect` block or color will not be applied on
  // the second or subsequent change to `surfaceMesh` (since the new `surfaceMesh` is itself
  // applied with `useEffect`).


  _react.default.useEffect(function () {
    console.log('init surfaceColor');

    if (surfaceRef.current) {
      surfaceRef.current.material.color.set(surfaceColor);
      renderScene();
    }
  }, [renderScene, surfaceColor, surfaceMesh]);

  if (surfaceRef.current) {
    surfaceRef.current.visible = useSurface;
  } // When the window is resized, force an update to the camera aspect ratio as part of scene rendering.


  _react.default.useEffect(function () {
    var timeout;

    var handleResize = function handleResize() {
      clearTimeout(timeout); // Wait a bit before rendering to improve performance.s

      timeout = setTimeout(function () {
        var width = mountRef.current.clientWidth;
        var height = mountRef.current.clientHeight; // The `clientHeight` does not seem to change when resizing to a shorter height.
        // So keep track of the `innerHeight`, which does change, and use it for a correction.

        if (window.innerHeight < prevHeightRef.current) {
          height -= prevHeightRef.current - window.innerHeight;
        }

        prevHeightRef.current = window.innerHeight;
        rendererRef.current.setSize(width, height);
        cameraRef.current.aspect = width / height;
        cameraRef.current.updateProjectionMatrix();
        renderScene();
      }, 200);
    };

    window.addEventListener("resize", handleResize);
    return function () {
      return window.removeEventListener("resize", handleResize);
    };
  }, [renderScene]);

  if (rendererRef.current) {
    renderScene();
  }

  _react.default.useEffect(function () {
    if (interactionSpeedup > 1) {
      var setRes = function setRes(d) {
        rendererRef.current.setPixelRatio(window.devicePixelRatio / d);
        var width = mountRef.current.clientWidth;
        var height = mountRef.current.clientHeight;
        rendererRef.current.setSize(width, height);
        renderScene();
      };

      var mousedown = function mousedown() {
        return setRes(interactionSpeedup);
      };

      var mouseup = function mouseup() {
        return setRes(1);
      };

      rendererRef.current.domElement.addEventListener("mousedown", mousedown);
      rendererRef.current.domElement.addEventListener("mouseup", mouseup);
      return function () {
        rendererRef.current.domElement.removeEventListener("mousedown", mousedown);
        rendererRef.current.domElement.removeEventListener("mouseup", mouseup);
      };
    }

    return function () {};
  }, [interactionSpeedup, renderScene]); // Check for WebGL 2 support, and store the result, to avoid creating too may contexts
  // when checking with each rendering.


  var gl2Ref = _react.default.useRef(true);

  _react.default.useEffect(function () {
    gl2Ref.current = document.createElement("canvas").getContext("webgl2");
  }, [gl2Ref]);

  if (!gl2Ref.current) {
    return /*#__PURE__*/_react.default.createElement("div", {
      className: "Fallback"
    }, "WebGL 2 is not supported in this browser.");
  } // The `ref` here sets up the mounting of the Three.js renderer image in the
  // appropriate place in the DOM.


  return /*#__PURE__*/_react.default.createElement("div", {
    className: "Vol3dViewer",
    ref: mountRef
  });
}

Vol3dViewer.propTypes = {
  // A JavaScript `Uint8Array`
  volumeDataUint8: _propTypes.default.shape({
    buffer: _propTypes.default.shape({
      byteLength: _propTypes.default.number
    })
  }).isRequired,
  volumeSize: _propTypes.default.arrayOf(_propTypes.default.number).isRequired,
  voxelSize: _propTypes.default.arrayOf(_propTypes.default.number).isRequired,
  useVolumeMirrorX: _propTypes.default.bool,
  alphaScale: _propTypes.default.number,
  dtScale: _propTypes.default.number,
  // A Three.js `DataTexture` (https://threejs.org/docs/#api/en/textures/DataTexture)
  transferFunctionTex: _propTypes.default.shape({
    type: _propTypes.default.number
  }).isRequired,
  finalGamma: _propTypes.default.number,
  interactionSpeedup: _propTypes.default.number,
  cameraPosition: _propTypes.default.arrayOf(_propTypes.default.number),
  cameraTarget: _propTypes.default.arrayOf(_propTypes.default.number),
  cameraUp: _propTypes.default.arrayOf(_propTypes.default.number),
  cameraFovDegrees: _propTypes.default.number,
  orbitZoomSpeed: _propTypes.default.number,
  useLighting: _propTypes.default.bool,
  useSurface: _propTypes.default.bool,
  // A Three.js `Mesh` (https://threejs.org/docs/#api/en/objects/Mesh)
  surfaceMesh: _propTypes.default.shape({
    visible: _propTypes.default.bool
  }),
  surfaceColor: _propTypes.default.string,
  onCameraChange: _propTypes.default.func,
  onWebGLRender: _propTypes.default.func
};
Vol3dViewer.defaultProps = {
  useVolumeMirrorX: false,
  alphaScale: 1.0,
  dtScale: 1.0,
  finalGamma: 4.5,
  interactionSpeedup: 1,
  cameraPosition: [0, 0, -1],
  cameraTarget: [0, 0, 0],
  // Gives the correct orientation for Janelia FlyLight datasets.
  cameraUp: [0, -1, 0],
  cameraFovDegrees: 45.0,
  orbitZoomSpeed: 0.15,
  useLighting: true,
  useSurface: false,
  surfaceMesh: null,
  surfaceColor: '#00ff00',
  onCameraChange: null,
  onWebGLRender: null
};
var _default = Vol3dViewer;
exports.default = _default;