text: import Cartesian3 from "../Core/Cartesian3.js";
  import Color from "../Core/Color.js";
  import ColorGeometryInstanceAttribute from "../Core/ColorGeometryInstanceAttribute.js";
  import defaultValue from "../Core/defaultValue.js";
  import defined from "../Core/defined.js";
  import destroyObject from "../Core/destroyObject.js";
  import DeveloperError from "../Core/DeveloperError.js";
  import FrustumGeometry from "../Core/FrustumGeometry.js";
  import FrustumOutlineGeometry from "../Core/FrustumOutlineGeometry.js";
  import GeometryInstance from "../Core/GeometryInstance.js";
  import Matrix3 from "../Core/Matrix3.js";
  import OrthographicFrustum from "../Core/OrthographicFrustum.js";
  import OrthographicOffCenterFrustum from "../Core/OrthographicOffCenterFrustum.js";
  import PerspectiveFrustum from "../Core/PerspectiveFrustum.js";
  import PerspectiveOffCenterFrustum from "../Core/PerspectiveOffCenterFrustum.js";
  import Quaternion from "../Core/Quaternion.js";
  import PerInstanceColorAppearance from "./PerInstanceColorAppearance.js";
  import Primitive from "./Primitive.js";
  
  /**
   * Draws the outline of the camera's view frustum.
   *
   * @alias DebugCameraPrimitive
   * @constructor
   *
   * @param {Object} options Object with the following properties:
   * @param {Camera} options.camera The camera.
   * @param {Number[]} [options.frustumSplits] Distances to the near and far planes of the camera frustums. This overrides the camera's frustum near and far values.
   * @param {Color} [options.color=Color.CYAN] The color of the debug outline.
   * @param {Boolean} [options.updateOnChange=true] Whether the primitive updates when the underlying camera changes.
   * @param {Boolean} [options.show=true] Determines if this primitive will be shown.
   * @param {Object} [options.id] A user-defined object to return when the instance is picked with {@link Scene#pick}.
   *
   * @example
   * primitives.add(new Cesium.DebugCameraPrimitive({
   *   camera : camera,
   *   color : Cesium.Color.YELLOW
   * }));
   */
  function DebugCameraPrimitive(options) {
    options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  
    //>>includeStart('debug', pragmas.debug);
    if (!defined(options.camera)) {
      throw new DeveloperError("options.camera is required.");
    }
    //>>includeEnd('debug');
  
    this._camera = options.camera;
    this._frustumSplits = options.frustumSplits;
    this._color = defaultValue(options.color, Color.CYAN);
    this._updateOnChange = defaultValue(options.updateOnChange, true);
  
    /**
     * Determines if this primitive will be shown.
     *
     * @type Boolean
     * @default true
     */
    this.show = defaultValue(options.show, true);
  
    /**
     * User-defined value returned when the primitive is picked.
     *
     * @type {*}
     * @default undefined
     *
     * @see Scene#pick
     */
    this.id = options.id;
    this._id = undefined;
  
    this._outlinePrimitives = [];
    this._planesPrimitives = [];
  }
  
  var scratchRight = new Cartesian3();
  var scratchRotation = new Matrix3();
  var scratchOrientation = new Quaternion();
  var scratchPerspective = new PerspectiveFrustum();
  var scratchPerspectiveOffCenter = new PerspectiveOffCenterFrustum();
  var scratchOrthographic = new OrthographicFrustum();
  var scratchOrthographicOffCenter = new OrthographicOffCenterFrustum();
  
  var scratchColor = new Color();
  var scratchSplits = [1.0, 100000.0];
  
  /**
   * @private
   */
  DebugCameraPrimitive.prototype.update = function (frameState) {
    if (!this.show) {
      return;
    }
  
    var planesPrimitives = this._planesPrimitives;
    var outlinePrimitives = this._outlinePrimitives;
    var i;
    var length;
  
    if (this._updateOnChange) {
      // Recreate the primitive every frame
      length = planesPrimitives.length;
      for (i = 0; i < length; ++i) {
        outlinePrimitives[i] =
          outlinePrimitives[i] && outlinePrimitives[i].destroy();
        planesPrimitives[i] =
          planesPrimitives[i] && planesPrimitives[i].destroy();
      }
      planesPrimitives.length = 0;
      outlinePrimitives.length = 0;
    }
  
    if (planesPrimitives.length === 0) {
      var camera = this._camera;
      var cameraFrustum = camera.frustum;
      var frustum;
      if (cameraFrustum instanceof PerspectiveFrustum) {
        frustum = scratchPerspective;
      } else if (cameraFrustum instanceof PerspectiveOffCenterFrustum) {
        frustum = scratchPerspectiveOffCenter;
      } else if (cameraFrustum instanceof OrthographicFrustum) {
        frustum = scratchOrthographic;
      } else {
        frustum = scratchOrthographicOffCenter;
      }
      frustum = cameraFrustum.clone(frustum);
  
      var numFrustums;
      var frustumSplits = this._frustumSplits;
      if (!defined(frustumSplits) || frustumSplits.length <= 1) {
        // Use near and far planes if no splits created
        frustumSplits = scratchSplits;
        frustumSplits[0] = this._camera.frustum.near;
        frustumSplits[1] = this._camera.frustum.far;
        numFrustums = 1;
      } else {
        numFrustums = frustumSplits.length - 1;
      }
  
      var position = camera.positionWC;
      var direction = camera.directionWC;
      var up = camera.upWC;
      var right = camera.rightWC;
      right = Cartesian3.negate(right, scratchRight);
  
      var rotation = scratchRotation;
      Matrix3.setColumn(rotation, 0, right, rotation);
      Matrix3.setColumn(rotation, 1, up, rotation);
      Matrix3.setColumn(rotation, 2, direction, rotation);
  
      var orientation = Quaternion.fromRotationMatrix(
        rotation,
        scratchOrientation
      );
  
      planesPrimitives.length = outlinePrimitives.length = numFrustums;
  
      for (i = 0; i < numFrustums; ++i) {
        frustum.near = frustumSplits[i];
        frustum.far = frustumSplits[i + 1];
  
        planesPrimitives[i] = new Primitive({
          geometryInstances: new GeometryInstance({
            geometry: new FrustumGeometry({
              origin: position,
              orientation: orientation,
              frustum: frustum,
              _drawNearPlane: i === 0,
            }),
            attributes: {
              color: ColorGeometryInstanceAttribute.fromColor(
                Color.fromAlpha(this._color, 0.1, scratchColor)
              ),
            },
            id: this.id,
            pickPrimitive: this,
          }),
          appearance: new PerInstanceColorAppearance({
            translucent: true,
            flat: true,
          }),
          asynchronous: false,
        });
  
        outlinePrimitives[i] = new Primitive({
          geometryInstances: new GeometryInstance({
            geometry: new FrustumOutlineGeometry({
              origin: position,
              orientation: orientation,
              frustum: frustum,
              _drawNearPlane: i === 0,
            }),
            attributes: {
              color: ColorGeometryInstanceAttribute.fromColor(this._color),
            },
            id: this.id,
            pickPrimitive: this,
          }),
          appearance: new PerInstanceColorAppearance({
            translucent: false,
            flat: true,
          }),
          asynchronous: false,
        });
      }
    }
  
    length = planesPrimitives.length;
    for (i = 0; i < length; ++i) {
      outlinePrimitives[i].update(frameState);
      planesPrimitives[i].update(frameState);
    }
  };
  
  /**
   * Returns true if this object was destroyed; otherwise, false.
   * <p>
   * If this object was destroyed, it should not be used; calling any function other than
   * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
   * </p>
   *
   * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
   *
   * @see DebugCameraPrimitive#destroy
   */
  DebugCameraPrimitive.prototype.isDestroyed = function () {
    return false;
  };
  
  /**
   * Destroys the WebGL resources held by this object.  Destroying an object allows for deterministic
   * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
   * <p>
   * Once an object is destroyed, it should not be used; calling any function other than
   * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.  Therefore,
   * assign the return value (<code>undefined</code>) to the object as done in the example.
   * </p>
   *
   * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
   *
   * @example
   * p = p && p.destroy();
   *
   * @see DebugCameraPrimitive#isDestroyed
   */
  DebugCameraPrimitive.prototype.destroy = function () {
    var length = this._planesPrimitives.length;
    for (var i = 0; i < length; ++i) {
      this._outlinePrimitives[i] =
        this._outlinePrimitives[i] && this._outlinePrimitives[i].destroy();
      this._planesPrimitives[i] =
        this._planesPrimitives[i] && this._planesPrimitives[i].destroy();
    }
    return destroyObject(this);
  };
  export default DebugCameraPrimitive;
  