@Override
  public void closeAndDispose() {
    if (alreadyClosing) return;
    alreadyClosing = true;

    this.cameraMount = null;
    this.viewportAdapter = null;
    if (cameraTrackAndDollyVariablesHolder != null) {
      cameraTrackAndDollyVariablesHolder.closeAndDispose();
      cameraTrackAndDollyVariablesHolder = null;
    }
    graphics3dAdapter = null;
  }
  @Override
  public void update() {
    if (graphics3dAdapter.getContextManager().getCurrentViewport() != viewportAdapter) {
      forward = false;
      backward = false;
      left = false;
      right = false;
      up = false;
      down = false;
    }

    if (isTracking) {
      if (isTrackingX) {
        double trackX = cameraTrackAndDollyVariablesHolder.getTrackingX();
        if (!Double.isNaN(trackX)) fixX = trackX + trackDX;
      }

      if (isTrackingY) {
        double trackY = cameraTrackAndDollyVariablesHolder.getTrackingY();
        if (!Double.isNaN(trackY)) fixY = trackY + trackDY;
      }

      if (isTrackingZ) {
        double trackZ = cameraTrackAndDollyVariablesHolder.getTrackingZ();
        if (!Double.isNaN(trackZ)) fixZ = trackZ + trackDZ;
      }
    }

    if (isDolly) {
      double dollyX = cameraTrackAndDollyVariablesHolder.getDollyX();
      if (isDollyX) {
        if (!Double.isNaN(dollyX)) camX = dollyX + dollyDX;
      }

      if (isDollyY) {
        double dollyY = cameraTrackAndDollyVariablesHolder.getDollyY();
        if (!Double.isNaN(dollyY)) camY = dollyY + dollyDY;
      }

      if (isDollyZ) {
        double dollyZ = cameraTrackAndDollyVariablesHolder.getDollyZ();
        if (!Double.isNaN(dollyZ)) camZ = dollyZ + dollyDZ;
      }
    }

    double fieldOfView = cameraTrackAndDollyVariablesHolder.getFieldOfView();
    if (!Double.isNaN(fieldOfView)) setFieldOfView(fieldOfView);

    // Flying
    if (fly && !isTracking && !isDolly && !transitioning) {
      if (forward) {
        moveCameraForward(-0.5);
      }

      if (backward) {
        moveCameraForward(0.5);
      }

      if (left) {
        pan(20, 0);
      }

      if (right) {
        pan(-20, 0);
      }

      if (up) {
        pan(00, 20);
      }

      if (down) {
        pan(00, -20);
      }
    }

    // End Flying

    if (transitioning && !isTracking && !isDolly) {
      int numberOfDimensionsThatHaveTransitioned = 0;
      double elapsedTransitionTime = System.currentTimeMillis() - lastTransitionTime;
      lastTransitionTime = System.currentTimeMillis();

      if (Math.abs(camX - storedCameraPositions.get(storedPositionIndex).getX())
          <= Math.abs(camXSpeed * elapsedTransitionTime)) {
        camX = storedCameraPositions.get(storedPositionIndex).getX();
        numberOfDimensionsThatHaveTransitioned++;
      } else {
        camX += camXSpeed * elapsedTransitionTime;
      }

      if (Math.abs(camY - storedCameraPositions.get(storedPositionIndex).getY())
          <= Math.abs(camYSpeed * elapsedTransitionTime)) {
        camY = storedCameraPositions.get(storedPositionIndex).getY();
        numberOfDimensionsThatHaveTransitioned++;
      } else {
        camY += camYSpeed * elapsedTransitionTime;
      }

      if (Math.abs(camZ - storedCameraPositions.get(storedPositionIndex).getZ())
          <= Math.abs(camZSpeed * elapsedTransitionTime)) {
        camZ = storedCameraPositions.get(storedPositionIndex).getZ();
        numberOfDimensionsThatHaveTransitioned++;
      } else {
        camZ += camZSpeed * elapsedTransitionTime;
      }

      if (Math.abs(fixX - storedFixPositions.get(storedPositionIndex).getX())
          <= Math.abs(fixXSpeed * elapsedTransitionTime)) {
        fixX = storedFixPositions.get(storedPositionIndex).getX();
        numberOfDimensionsThatHaveTransitioned++;
      } else {
        fixX += fixXSpeed * elapsedTransitionTime;
      }

      if (Math.abs(fixY - storedFixPositions.get(storedPositionIndex).getY())
          <= Math.abs(fixYSpeed * elapsedTransitionTime)) {
        fixY = storedFixPositions.get(storedPositionIndex).getY();
        numberOfDimensionsThatHaveTransitioned++;
      } else {
        fixY += fixYSpeed * elapsedTransitionTime;
      }

      if (Math.abs(fixZ - storedFixPositions.get(storedPositionIndex).getZ())
          <= Math.abs(fixZSpeed * elapsedTransitionTime)) {
        fixZ = storedFixPositions.get(storedPositionIndex).getZ();
        numberOfDimensionsThatHaveTransitioned++;
      } else {
        fixZ += fixZSpeed * elapsedTransitionTime;
      }

      if (numberOfDimensionsThatHaveTransitioned == 6) {
        transitioning = false;
      }
    }
  }
 @Override
 public double getDollyZVar() {
   return cameraTrackAndDollyVariablesHolder.getDollyZ();
 }
 @Override
 public double getTrackYVar() {
   return cameraTrackAndDollyVariablesHolder.getTrackingY();
 }